El decorador de propiedades de Python

E

A menudo se considera una buena práctica crear captadores y definidores para las propiedades públicas de una clase. Muchos lenguajes le permiten implementar esto de diferentes maneras, ya sea usando una función (como person.getName()), o mediante el uso de un idioma específico get o set construir. En Python, se hace usando @property.

En este artículo, describiré el decorador de propiedades de Python, que es posible que haya visto que se usa con el @decorator sintaxis:

class Person(object):
    def __init__(self, first_name, last_name):
        self.first_name = first_name
        self.last_name = last_name

    @property
    def full_name(self):
        return self.first_name + ' ' + self.last_name

    @full_name.setter
    def full_name(self, value):
        first_name, last_name = value.split(' ')
        self.first_name = first_name
        self.last_name = last_name

    @full_name.deleter
    def full_name(self):
        del self.first_name
        del self.last_name

Esta es la forma en que Python crea captadores, definidores y eliminadores (o métodos mutantes) para una propiedad en una clase.

En este caso, el @property decorador lo hace para que llames al full_name(self) método como si fuera una propiedad normal, cuando en realidad es un método que contiene código que se ejecutará cuando se establezca la propiedad.

El uso de un captador / definidor / eliminador como este nos proporciona bastantes ventajas, algunas de las cuales he enumerado aquí:

  • Validación: antes de configurar la propiedad interna, puede validar que el valor proporcionado cumple con algunos criterios y hacer que arroje un error si no lo hace.
  • Carga diferida: los recursos pueden cargado perezosamente aplazar el trabajo hasta que sea realmente necesario, ahorrando tiempo y recursos
  • Abstracción: los captadores y definidores le permiten abstraer la representación interna de los datos. Como en nuestro ejemplo anterior, por ejemplo, los nombres y apellidos se almacenan por separado, pero los captadores y definidores contienen la lógica que usa el nombre y los apellidos para crear el nombre completo.
  • Depuración: dado que los métodos mutadores pueden encapsular cualquier código, se convierte en un gran lugar para la interceptación al depurar (o registrar) su código. Por ejemplo, puede registrar o inspeccionar cada vez que se cambia el valor de una propiedad.

Python logra esta funcionalidad con decoradores, que son métodos especiales que se utilizan para cambiar el comportamiento de otra función o clase. Para describir cómo @property decorador funciona, echemos un vistazo a un decorador más simple y cómo funciona internamente.

Un decorador es simplemente una función que toma otra función como argumento y la agrega a su comportamiento envolviéndola. He aquí un ejemplo sencillo:

# decorator.py

def some_func():
    print 'Hey, you guys'

def my_decorator(func):
    def inner():
        print 'Before func!'
        func()
        print 'After func!'

    return inner

print 'some_func():'
some_func()

print ''

some_func_decorated = my_decorator(some_func)

print 'some_func() with decorator:'
some_func_decorated()

Ejecutar este código te da:

$ python decorator.py
some_func():
Hey, you guys

some_func() with decorator:
Before func!
Hey, you guys
After func!

Como puede ver, el my_decorator() function crea dinámicamente una nueva función para regresar usando la función de entrada, agregando código para ser ejecutado antes y después de que se ejecute la función original.

los property El decorador se implementa con un patrón similar al my_decorator función. Usando Python @decorator sintaxis, recibe la función decorada como argumento, como en mi ejemplo: some_func_decorated = my_decorator(some_func).

Entonces, volviendo a mi primer ejemplo, este código:

@property
def full_name_getter(self):
    return self.first_name + ' ' + self.last_name

Es aproximadamente equivalente a esto:

def full_name_getter(self):
    return self.first_name + ' ' + self.last_name

full_name = property(full_name_getter)

Tenga en cuenta que cambié algunos nombres de funciones para mayor claridad.

Luego, más tarde, cuando quieras usar @full_name.setter como hacemos en el ejemplo, lo que realmente estás llamando es:

def full_name_setter(self, value):
    first_name, last_name = value.split(' ')
    self.first_name = first_name
    self.last_name = last_name

full_name = property(full_name_getter)
full_name = full_name.setter(full_name_setter)

Ahora esta nueva full_name objeto (una instancia del property object) tiene métodos getter y setter.

Para usarlos con nuestra clase, Person, la property El objeto actúa como un descriptor, lo que significa que tiene su propio __obtener__(), __conjunto__() y __Eliminar__() métodos. los __get__() y __set__() Los métodos se activan en un objeto cuando se recupera o establece una propiedad, y __delete__() se activa cuando se elimina una propiedad con del.

Entonces person.full_name="Billy Bob" desencadena el __set__() método, que fue heredado de object. Esto nos lleva a un punto importante: su clase debe heredar de object para que esto funcione. Entonces una clase como esta no ser capaz de utilizar las propiedades del setter ya que no hereda de object:

class Person:
    pass

Gracias a property, estos métodos ahora corresponden a nuestro full_name_getter y full_name_setter métodos de arriba:

full_name.fget is full_name_getter    # True
full_name.fset is full_name_setter    # True

fget y fset ahora están envueltos por .__get__() y .__set__(), respectivamente.

Y finalmente, se puede acceder a estos objetos descriptores pasando una referencia a nuestra clase, Person:

>>> person = Person('Billy', 'Bob')
>>> 
>>> full_name.__get__(person)
Billy Bob
>>>
>>> full_name.__set__(person, 'Timmy Thomas')
>>>
>>> person.first_name
Timmy
>>> person.last_name
Thomas

Así es esencialmente como funcionan las propiedades debajo de la superficie.

 

About the author

Ramiro de la Vega

Bienvenido a Pharos.sh

Soy Ramiro de la Vega, Estadounidense con raíces Españolas. Empecé a programar hace casi 20 años cuando era muy jovencito.

Espero que en mi web encuentres la inspiración y ayuda que necesitas para adentrarte en el fantástico mundo de la programación y conseguir tus objetivos por difíciles que sean.

Add comment

Sobre mi

Últimos Post

Etiquetas

Esta web utiliza cookies propias y de terceros para su correcto funcionamiento y para fines analíticos y para mostrarte publicidad relacionada con tus preferencias en base a un perfil elaborado a partir de tus hábitos de navegación. Al hacer clic en el botón Aceptar, aceptas el uso de estas tecnologías y el procesamiento de tus datos para estos propósitos. Más información
Privacidad