2010-09-23 15 views
7

¿Cuál es el motivo para usar la variable self._age? ¿Un nombre similar que no se vincula con el self.age ya utilizado?Propiedades en Python

class newprops(object): 
    def getage(self): 
     return 40 
    def setage(self, value): 
     self._age = value 
    age = property(getage, setage, None, None) 
+7

'40' retorno - me recuerda generador de números aleatorios de xkcd! – katrielalex

Respuesta

11

self.age ya está ocupado por la propiedad, debe dar otro nombre a la variable real, que es _age aquí.

Por cierto, ya que Python 2.6, se podría escribir esto con decoradores:

def newprops(object): 

    @property 
    def age(self): 
     return 40 

    @age.setter 
    def age(self, value): 
     self._age = value 
+3

Usar un nombre que comience con un guión bajo tiene otra ventaja: es la convención de nomenclatura comúnmente reconocida para las cosas "privadas" (= "no tocar a menos que deba hacerlo"). – delnan

+0

Y usar un nombre que comience con un doble guión bajo es la convención comúnmente reconocida para "realmente privado". En una de las verrugas más desagradables de Python, los nombres de doble guión bajo están destrozados, de modo que ni siquiera puedes invocarlos a menos que hagas un truco tú mismo. – katrielalex

+0

@delnan: Prefiero decir que es la convención para "protegidos", y los programadores demasiado cautelosos usan la función de creación de nombres pseudo-privada para simular de algún modo las variables "privadas". – AndiDog

0

Lo que escribió nunca se escribiría en python. Muchas veces, sin embargo, hay acciones que deben realizarse al guardar una propiedad (como la serialización), y esto se puede almacenar en caché de forma transparente en una propiedad.

Dado que el protocolo para llamar a una propiedad y acceder a un miembro es el mismo, el estilo python es esperar el mayor tiempo posible para convertir las variables miembro en propiedades.

+0

"Lo que escribiste nunca se escribiría en python". Dile eso a Mark Lutz. ¡Lo escribió en su libro! – MrMas

4

Su ejemplo es en realidad sin sentido porque el comprador devuelve una constante. Una variable de subrayado-llamado separada en que generalmente se usa en conjunción con propiedades, que puede ser

1) de sólo lectura

class C(object): 
    @property 
    def age(self): 
     return self._age 

En este caso, instance.age sólo puede ser leída pero no asignado. La convención es escribir internamente en self._age.

2) lectura y escritura

class C(object): 
    @property 
    def age(self): 
     return self._age 

    @age.setter 
    def age(self, value): 
     assert value >= 0 
     self._age = value 

Tener captador y colocador sólo tiene sentido si se tiene que hacer cálculos o comprobaciones adicionales al asignar el valor. De lo contrario, simplemente podría declarar la variable sin el guión bajo, ya que las propiedades y las variables de instancia se acceden de la misma manera (en términos de código). Es por eso que _age y la propiedad age por supuesto deben tener un nombre diferente.

+0

¡correcto! Gracias. Estoy repasando este libro, y ese fue el ejemplo ... Yo era como la WTF, ¿de dónde vino esto? – shawn

+0

en el primer ejemplo, 'instance.age' ciertamente se puede asignar a. Pruebe 'instance.age = sqlite3.connect (': memory:')'. porque no define un '__set__', cualquier asignación va directamente a las instancias' __dict__' y futuros intentos de acceder al descriptor van directamente a '__dict__'. – aaronasterling

+0

si quiere una propiedad de solo lectura, defina '__set__' como' raise AttributeError' – aaronasterling

6

Algunos lenguajes orientados a objetos tienen lo que se llama atributos privados, a los que no se puede acceder desde fuera de los métodos de clase. Esto es importante porque algunos atributos no están destinados a ser cambiados directamente, en cambio, están destinados a ser cambiados como una función de otra cosa, o validados antes de ser cambiados. En Python no tiene los atributos privados , pero puede implementar algo similar usando getters y setters para una variable que comienza con guión bajo: la convención de Python para los métodos y atributos privados.

Por ejemplo. La hipotenusa de un triángulo rectangular está dada por h=sqrt(a*a+b*b), por lo que no puede cambiar h directamente porque la relación debe mantenerse. Además, diga que un nombre debe estar en el formato LASTNAME COMMA FIRSTNAME, luego debe verificar que este sea el caso antes de asignar self.lastname.

El captador de propiedad le permite obtener la hipotenusa, pero le impide configurarla. El ajustador de propiedades le permite establecer una propiedad, pero puede realizar comprobaciones antes de establecer realmente la propiedad.

Así:

class Person(object) 
def __init__(self): 
    # The actual attribute is _name 
    self._name = None 
@property 
def name(self): 
    # when I ask for the name, I mean to get _name 
    return self._name 
@name.setter 
def name(self, value): 
    # before setting name I can ensure that it has the right format 
    if regex_name.match(value): 
    # assume you have a regular expression to check for the name 
    self._name = value 
    else: 
    raise ValueError('invalid name') 

Otro ejemplo:

class Triangle(object): 
def __init__(self, a, b): 
    # here a and b do not need to be private because 
    # we can change them at will. However, you could 
    # make them private and ensure that they are floats 
    # when they are changed 
    self.a = a 
    self.b = b 
@property 
def h(self): 
    return math.sqrt(a*a+b*b) 
# notice there is no h.setter - you cannot set h directly 
+2

Excelentes ejemplos, comentarios efectivos. – Air

Cuestiones relacionadas