Saltar al contenido

¿Cómo funciona el decorador @property en Python?

No olvides que en la informática un error casi siempere puede tener más de una soluciones, de igual modo nosotros enseñamos lo más óptimo y mejor.

Solución:

los property() función devuelve un objeto descriptor especial:

>>> property()

Es este objeto el que tiene extra métodos:

>>> property().getter

>>> property().setter

>>> property().deleter

Estos actúan como decoradores. también. Devuelven un nuevo objeto de propiedad:

>>> property().getter(None)

esa es una copia del objeto anterior, pero con una de las funciones reemplazadas.

Recuerda, que el @decorator la sintaxis es simplemente azúcar sintáctica; la sintaxis:

@property
def foo(self): return self._foo

realmente significa lo mismo que

def foo(self): return self._foo
foo = property(foo)

entonces foo la función es reemplazada por property(foo), que vimos arriba es un objeto especial. Entonces cuando usas @foo.setter()lo que estás haciendo es llamar así property().setter El método que le mostré anteriormente, que devuelve una nueva copia de la propiedad, pero esta vez con la función setter reemplazada por el método decorado.

La siguiente secuencia también crea una propiedad completa mediante el uso de esos métodos de decorador.

Primero creamos algunas funciones y un property objeto con solo un getter:

>>> def getter(self): print('Get!')
... 
>>> def setter(self, value): print('Set to !r!'.format(value))
... 
>>> def deleter(self): print('Delete!')
... 
>>> prop = property(getter)
>>> prop.fget is getter
True
>>> prop.fset is None
True
>>> prop.fdel is None
True

A continuación usamos el .setter() método para agregar un setter:

>>> prop = prop.setter(setter)
>>> prop.fget is getter
True
>>> prop.fset is setter
True
>>> prop.fdel is None
True

Por último, agregamos un eliminador con el .deleter() método:

>>> prop = prop.deleter(deleter)
>>> prop.fget is getter
True
>>> prop.fset is setter
True
>>> prop.fdel is deleter
True

Por último, pero no menos importante, el property objeto actúa como un objeto descriptor, por lo que tiene .__get__(), .__set__() y .__delete__() métodos para enganchar a la instancia attribute obteniendo, configurando y eliminando:

>>> class Foo: pass
... 
>>> prop.__get__(Foo(), Foo)
Get!
>>> prop.__set__(Foo(), 'bar')
Set to 'bar'!
>>> prop.__delete__(Foo())
Delete!

El Descriptor Howto incluye una implementación de muestra de Python puro del property() escribe:

class Property:
    "Emulate PyProperty_Type() in Objects/descrobject.c"

    def __init__(self, fget=None, fset=None, fdel=None, doc=None):
        self.fget = fget
        self.fset = fset
        self.fdel = fdel
        if doc is None and fget is not None:
            doc = fget.__doc__
        self.__doc__ = doc

    def __get__(self, obj, objtype=None):
        if obj is None:
            return self
        if self.fget is None:
            raise AttributeError("unreadable attribute")
        return self.fget(obj)

    def __set__(self, obj, value):
        if self.fset is None:
            raise AttributeError("can't set attribute")
        self.fset(obj, value)

    def __delete__(self, obj):
        if self.fdel is None:
            raise AttributeError("can't delete attribute")
        self.fdel(obj)

    def getter(self, fget):
        return type(self)(fget, self.fset, self.fdel, self.__doc__)

    def setter(self, fset):
        return type(self)(self.fget, fset, self.fdel, self.__doc__)

    def deleter(self, fdel):
        return type(self)(self.fget, self.fset, fdel, self.__doc__)

La documentación dice que es solo un atajo para crear propiedades de solo lectura. Entonces

@property
def x(self):
    return self._x

es equivalente a

def getx(self):
    return self._x
x = property(getx)

Aquí hay un ejemplo mínimo de cómo @property puede ser implementado:

class Thing:
    def __init__(self, my_word):
        self._word = my_word 
    @property
    def word(self):
        return self._word

>>> print( Thing('ok').word )
'ok'

De lo contrario word sigue siendo un método en lugar de una propiedad.

class Thing:
    def __init__(self, my_word):
        self._word = my_word
    def word(self):
        return self._word

>>> print( Thing('ok').word() )
'ok'

Si para ti ha sido de ayuda nuestro post, sería de mucha ayuda si lo compartes con más entusiastas de la programación así nos ayudas a dar difusión a nuestro contenido.

¡Haz clic para puntuar esta entrada!
(Votos: 0 Promedio: 0)



Utiliza Nuestro Buscador

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *