73 votes

Comment fonctionnent les propriétés Python?

J'ai utilisé avec succès les propriétés Python, mais je ne vois pas comment elles pourraient fonctionner. Si je déréférence une propriété en dehors d'une classe, je viens d'obtenir un objet de type property :

 >>> @property
... def hello(): return "Hello, world!"
...
>>> hello
<property object at 0x9870a8>
 

Mais si je mets une propriété dans une classe, le comportement est très différent:

 >>> class Foo(object):
...   @property
...   def hello(self): return "Hello, world!"
...
>>> Foo().hello
'Hello, world!'
 

J'ai remarqué que Foo.hello non lié est toujours l'objet property , donc l'instanciation de classe doit faire la magie, mais quelle magie est-ce?

50voto

Tim Yates Points 2415

Comme d'autres l'ont noté, ils utilisent un langage appelé descripteurs.

La raison que la propriété réelle de l'objet est renvoyé lorsque vous accédez par l'intermédiaire d'une classe Hello.foo réside dans la façon dont la propriété implémente l' __get__(self, instance, owner) méthode spéciale. Si un descripteur est accessible sur un exemple, alors que l'instance est passé comme approprié argument, et owner est la classe de l'instance.

D'autre part, si elle est accessible par la classe, alors instance est None et seulement owner est passé. L' property objet reconnaît cela et renvoie self.


Outre les Descripteurs howto, voir aussi la documentation sur la mise en Œuvre de Descripteurs et en Invoquant des Descripteurs dans le Guide de Langue.

22voto

Timothy Vann Points 147

Pour que @properties fonctionne correctement, la classe doit être une sous-classe d' objet . lorsque la classe n'est pas une sous-classe d' objet, la première fois que vous essayez d'accéder au setter, elle crée en fait un nouvel attribut avec le nom plus court au lieu d'accéder via le setter.

Ce qui suit ne fonctionne pas correctement.

 class C(): # <-- Notice that object is missing

    def __init__(self):
        self._x = None

    @property
    def x(self):
        print 'getting value of x'
        return self._x

    @x.setter
    def x(self, x):
        print 'setting value of x'
        self._x = x

>>> c = C()
>>> c.x = 1
>>> print c.x, c._x
1 0
 

Ce qui suit fonctionnera correctement

 class C(object):

    def __init__(self):
        self._x = None

    @property
    def x(self):
        print 'getting value of x'
        return self._x

    @x.setter
    def x(self, x):
        print 'setting value of x'
        self._x = x

>>> c = C()
>>> c.x = 1
setting value of x
>>> print c.x, c._x
getting value of x
1 1
 

11voto

Sven Marnach Points 133943

Les propriétés sont des descripteurs , et les descripteurs se comportent spécialement quand ils sont membres d'une instance de classe. En bref, si a est une instance de type A , et A.foo est un descripteur, alors a.foo est équivalent à A.foo.__get__(a) .

2voto

Achim Points 6912

L'objet property implémente simplement le protocole de descripteur: http://docs.python.org/howto/descriptor.html

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X