2011-09-10 14 views

Respuesta

116

Las propiedades son una clase especial de atributo. Básicamente, cuando Python se encuentra con el siguiente código:

spam = SomeObject() 
print(spam.eggs) 

que mira hacia arriba en eggsspam, y luego examina eggs para ver si tiene un __get__, __set__, o __delete__ método y thinsp; — & thinsp; si lo hace, es una propiedad. Si es una propiedad, en lugar de simplemente devolver el objeto eggs (como lo haría con cualquier otro atributo) llamará al método __get__ (ya que estábamos haciendo la búsqueda) y devolverá el método que devuelva.

Más información sobre Python's data model and descriptors.

+8

La mejor respuesta de todo el conjunto, no menos importante, ya que brinda buenos detalles concretos sobre cómo Python maneja esto en el back-end. +1. :) –

17

En términos generales, una propiedad y un atributo son la misma cosa. Sin embargo, hay un decorador de propiedades en Python que proporciona acceso getter/setter a un atributo (u otros datos).

class MyObject(object): 
    # This is a normal attribute 
    foo = 1 

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

    @bar.setter 
    def bar(self, value): 
     self.foo = value 


obj = MyObject() 
assert obj.foo == 1 
assert obj.bar == obj.foo 
obj.bar = 2 
assert obj.foo == 2 
assert obj.bar == obj.foo 
+0

podría por favor mencionar también el resultado esperado de este código? –

+0

¿Qué quieres decir? ¿No está eso en la parte inferior del código? – six8

28

Con una propiedad que tiene el control completo sobre sus getter, setter y Deleter métodos, que usted no tiene (si no usa advertencias) con un atributo.

class A(object): 
    _x = 0 
    '''A._x is an attribute''' 

    @property 
    def x(self): 
     ''' 
     A.x is a property 
     This is the getter method 
     ''' 
     return self._x 

    @x.setter 
    def x(self, value): 
     """ 
     This is the setter method 
     where I can check it's not assigned a value < 0 
     """ 
     if value < 0: 
      raise ValueError("Must be >= 0") 
     self._x = value 

>>> a = A() 
>>> a._x = -1 
>>> a.x = -1 
Traceback (most recent call last): 
    File "ex.py", line 15, in <module> 
    a.x = -1 
    File "ex.py", line 9, in x 
    raise ValueError("Must be >= 0") 
ValueError: Must be >= 0 
+0

Esto ("control completo") también se puede realizar con atributos "no-propiedad", sin estos simples decoradores. –

+1

lo que llamé una advertencia ... – neurino

+3

Me gusta que esta respuesta proporcione un ejemplo realista y útil. Siento que demasiadas respuestas en este sitio explican innecesariamente cómo funcionan las cosas en el back-end sin aclarar cómo el usuario debería interactuar con ellas. Si uno no entiende por qué/cuándo usar alguna funcionalidad, no tiene sentido saber cómo funciona detrás de las escenas. – Tom

11

La propiedad le permite obtener valores de consigna y como lo haría atributos normales, pero en el fondo hay un método que se llama traducirla en un getter y setter para usted. En realidad, es una gran ventaja reducir la repetición de llamados getters y setters.

Digamos, por ejemplo, que tenía una clase que contenía algunas coordenadas xey para algo que necesitaba. Para fijarlos es posible que desee hacer algo como:

myObj.x = 5 
myObj.y = 10 

Eso es mucho más fácil mirar y pensar en que escribir:

myObj.setX(5) 
myObj.setY(10) 

El problema es, ¿qué pasaría si un día los cambios de clase, tales que necesitas compensar tu xey con algún valor? Ahora necesitaría ingresar y cambiar la definición de su clase y todo el código que la llama, lo que podría ser muy lento y propenso a errores. La propiedad le permite usar la sintaxis anterior a la vez que le brinda la flexibilidad de cambiar la última.

En Python, puede definir getters, setters y eliminar métodos con la función de propiedad. Si solo desea la propiedad de lectura, también hay un decorador @property que puede agregar encima de su método.

http://docs.python.org/library/functions.html#property

1

aprendí 2 diferencias de site de Bernd Klein, en resumen:

1. La propiedad es una forma más conveniente de hacer la encapsulación de datos.

ex: Si tiene una longitud de atributo público de Object, más adelante, su proyecto requiere que lo encapsule, i.e: cambiarlo a privada y proporcionar get y set => tiene que cambiar muchos de los códigos que escribió antes:

#Old codes 
obj1.length=obj1.length+obj2.length 
#New codes(Using private attibutes and getter and setter) 
obj1.set_lenght(obj1.get_length()+obj2.get_length()) #=> this is ugly 

Si utiliza @property y lenght.setter @ => que no es necesario cambian los códigos viejos

2. Una propiedad puede encapsular múltiples atributos

class Person: 
    def __init__(self, name, physic_health, mental_health): 
    self.name=name 
    self.__physic_health=physic_health #physic_health is real value in range [0, 5.0] 
    self.__mental_health=mental_health #mental_health is real value in range [0, 5.0] 
    @property 
    def condition(self): 
    health=self.__physic_health+self.__mental_health 
    if(health<5.0): 
     return "I feel bad!" 
    elif health<8.0: 
     return "I am ok!" 
    else: 
     return "Great!" 

En este ejemplo, __physic_health y __mental_health son privadas y no se puede acceder directamente desde fuera sid e, la única forma fuera de clase interactuar con ellos es a través de la propiedad condition

0

También hay una diferencia no obvia que uso para almacenar en caché o datos, a menudo tenemos una función conectada al atributo de clase. Por ejemplo tengo que leer el archivo de una vez y mantener el contenido asignado al atributo de modo se almacena en caché el valor:

class Misc(): 
     def __init__(self): 
      self.test = self.test_func() 

     def test_func(self): 
      print 'func running' 
      return 'func value' 

cl = Misc() 
print cl.test 
print cl.test 

Salida:

func running 
func value 
func value 

Se puede acceder al atributo dos veces, pero nuestra función fue despedido sólo una vez. Cambiar el ejemplo anterior para utilizar la propiedad hará que el valor del atributo actualizar cada vez que se accede a él:

class Misc(): 

    @property 
    def test(self): 
     print 'func running' 
     return 'func value' 

cl = Misc() 
print cl.test 
print cl.test 

Salida:

func running 
func value 
func running 
func value 
Cuestiones relacionadas