Как работают свойства Python?
Я успешно использовал свойства Python, но я не вижу, как они могут работать. Если я разыскиваю свойство вне класса, я просто получаю объект типа property
:
@property
def hello(): return "Hello, world!"
hello # <property object at 0x9870a8>
Но если я помещаю свойство в класс, поведение очень отличается:
class Foo(object):
@property
def hello(self): return "Hello, world!"
Foo().hello # 'Hello, world!'
Я заметил, что unbound Foo.hello
все еще является объектом property
, поэтому создание экземпляра должно делать магию, но что это за магия?
Ответы
Ответ 1
Как отметили другие, они используют функцию языка, называемую дескрипторами.
Причина того, что реальный объект свойства возвращается при доступе к нему через класс Foo.hello
заключается в том, что свойство реализует специальный метод __get__(self, instance, owner)
:
- Если к экземпляру обращаются к экземпляру, то этот экземпляр передается как соответствующий аргумент, а
owner
является класс этого экземпляра. - Когда к нему обращаются через класс,
instance
имеет значение None, и передается только owner
. Объект property
распознает это и возвращает self
.
Помимо руководства по дескрипторам, см. Также документацию по реализации дескрипторов и вызову дескрипторов в руководстве по языку.
Ответ 2
Для корректной работы @properties класс должен быть подклассом объекта.
когда класс не является подклассом объекта, то при первом попытке доступа к установщику он фактически создает новый атрибут с более коротким именем вместо доступа через сеттер.
Ниже выполняется не.
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
Следующее будет работать правильно
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
Ответ 3
Свойства дескрипторы, и дескрипторы ведут себя особенно в случае члена экземпляра класса. Короче говоря, если a
- это экземпляр типа a
, а A.foo
- дескриптор, то A.foo
эквивалентен A.foo.__get__(a)
.
Ответ 4
Объект property
просто реализует протокол дескриптора: http://docs.python.org/howto/descriptor.html