Lo estoy haciendo así:
def set_property(property,value):
def get_property(property):
o
object.property = value
value = object.property
Soy nuevo en Python, por lo que todavía estoy explorando la sintaxis, y me gustaría obtener algunos consejos para hacerlo.
python
getter-setter
Jorge Guberte
fuente
fuente
._x
(que no es una propiedad, solo un atributo simple) omiten elproperty
ajuste. Solo referencias para.x
pasar por elproperty
.La forma "Pythonic" no es usar "getters" y "setters", sino usar atributos simples, como lo demuestra la pregunta, y
del
para eliminar (pero los nombres se cambian para proteger a los inocentes ... builtins):Si más tarde, desea modificar la configuración y la obtención, puede hacerlo sin tener que alterar el código de usuario, utilizando el
property
decorador:(Cada uso de decorador copia y actualiza el objeto de propiedad anterior, así que tenga en cuenta que debe usar el mismo nombre para cada conjunto, obtener y eliminar función / método.
Después de definir lo anterior, la configuración original, obtener y eliminar el código es el mismo:
Debes evitar esto:
En primer lugar, lo anterior no funciona, porque no proporciona un argumento para la instancia de que la propiedad se establecería en (generalmente
self
), que sería:En segundo lugar, esto duplica el propósito de dos métodos especiales,
__setattr__
y__getattr__
.En tercer lugar, también tenemos las funciones incorporadas
setattr
ygetattr
.El
@property
decorador es para crear captadores y colocadores.Por ejemplo, podríamos modificar el comportamiento de la configuración para colocar restricciones al valor que se establece:
En general, queremos evitar usar
property
y solo usar atributos directos.Esto es lo que esperan los usuarios de Python. Siguiendo la regla de la menor sorpresa, debe intentar dar a sus usuarios lo que esperan a menos que tenga una razón muy convincente de lo contrario.
Demostración
Por ejemplo, supongamos que necesitamos que el atributo protegido de nuestro objeto sea un número entero entre 0 y 100 inclusive, y evitar su eliminación, con mensajes apropiados para informar al usuario sobre su uso adecuado:
(Tenga en cuenta que se
__init__
refiere aself.protected_value
pero los métodos de propiedad se refierenself._protected_value
. Esto es para que__init__
use la propiedad a través de la API pública, asegurando que esté "protegida").Y uso:
¿Importan los nombres?
Si lo hacen .
.setter
y.deleter
hacer copias de la propiedad original. Esto permite que las subclases modifiquen correctamente el comportamiento sin alterar el comportamiento en el padre.Ahora para que esto funcione, debes usar los nombres respectivos:
No estoy seguro de dónde sería útil, pero el caso de uso es si desea una propiedad get, set y / o delete-only. Probablemente sea mejor quedarse semánticamente con la misma propiedad que tenga el mismo nombre.
Conclusión
Comience con atributos simples.
Si más tarde necesita funcionalidad en torno a la configuración, la obtención y la eliminación, puede agregarla con el decorador de propiedades.
Evite las funciones nombradas
set_...
yget_...
, para eso están las propiedades.fuente
__init__
método hace referenciaself.protected_value
pero el getter y los setters hacen referenciaself._protected_value
. ¿Podría explicar cómo funciona esto? Probé su código y funciona como está, así que esto no es un error tipográfico.__init__
.self.protected_value = start_protected_value
que en realidad está llamando a la función setter; Pensé que era una tarea.fuente
El uso
@property
y le@attribute.setter
ayuda a usar no solo la forma "pitónica" sino también a verificar la validez de los atributos tanto al crear el objeto como al modificarlo.Con esto, realmente 'oculta' el
_name
atributo de los desarrolladores del cliente y también realiza comprobaciones en el tipo de propiedad de nombre. Tenga en cuenta que siguiendo este enfoque, incluso durante el inicio, se llama al configurador. Entonces:Dará lugar a:
Pero:
fuente
Mira el
@property
decorador .fuente
Puede usar accesores / mutadores (es decir,
@attr.setter
y@property
) o no, pero lo más importante es ser coherente.Si está utilizando
@property
para acceder simplemente a un atributo, por ejemploúsalo para acceder a todos los * atributos! Sería una mala práctica acceder a algunos atributos usando
@property
y dejar algunas otras propiedades públicas (es decir, nombre sin guión bajo) sin un descriptor de acceso, por ejemplo , no lo haga.Tenga en cuenta que
self.b
no tiene un descriptor de acceso explícito aquí aunque sea público.De manera similar con los setters (o mutadores ), siéntase libre de usar, ¡
@attribute.setter
pero sea consistente! Cuando lo haces, por ejemploEs difícil para mí adivinar tu intención. Por un lado, estás diciendo que ambos
a
yb
son públicos (no hay un guión bajo en sus nombres), por lo que teóricamente se me debería permitir acceder / mutar (obtener / establecer) ambos. Pero luego especificas un mutador explícito solo paraa
, lo que me dice que tal vez no debería poder configurarb
. Dado que ha proporcionado un mutador explícito, no estoy seguro de si la falta de un descriptor de acceso explícito (@property
) significa que no debería poder acceder a ninguna de esas variables o si simplemente estaba siendo frugal en el uso@property
.* La excepción es cuando desea explícitamente hacer que algunas variables sean accesibles o mutables, pero no ambas, o desea realizar alguna lógica adicional al acceder o mutar un atributo. Esto es cuando estoy usando personalmente
@property
y@attribute.setter
(de lo contrario no hay acesores / mutadores explícitos para los atributos públicos).Por último, PEP8 y sugerencias de la Guía de estilo de Google:
PEP8, Diseñando para herencia dice:
Por otro lado, de acuerdo con las Reglas / Propiedades del lenguaje Python de la Guía de estilo de Google, la recomendación es:
Los pros de este enfoque:
y contras:
fuente
@property
, hacer que el resto también lo use@property
parece una mala decisión.@property
(por ejemplo, ejecutar alguna lógica especial antes de devolver un atributo). De lo contrario, ¿por qué decorarías un atributo@propery
y no otros?@property
para empezar, ¿verdad? Si tu getter esreturn this._x
y tu setter esthis._x = new_x
, entonces usarlo@property
es un poco tonto.@property
es ser consistente".Puedes usar los métodos mágicos
__getattribute__
y__setattr__
.Tenga en cuenta que
__getattr__
y__getattribute__
no son lo mismo.__getattr__
solo se invoca cuando no se encuentra el atributo.fuente