2013-04-03 2 views
19
class human(object): 
    def __init__(self, name=''): 
     self.name = name 

    @property 
    def name(self): 
     return self._name 

    @name.setter 
    def name(self, value): 
     self._name = value 

class superhuman(human): 
    @property 
    def name(self): 
     return 'super ' + name 

s = superhuman('john') 
print s.name 

# Doesn't work :("AttributeError: can't set attribute" 
s.name = 'jack' 
print s.name 

Я хочу, чтобы иметь возможность переопределить свойство, но иметь возможность использовать сеттер суперпользователя без необходимости переопределять сеттер в дочернем классе.Python overriding getter without setter

Возможно ли это в pythonicaly?

ответ

33

Используйте только.getter декоратора оригинального объекта:

class superhuman(human): 
    @human.name.getter 
    def name(self): 
     return 'super ' + self._name 

Обратите внимание, что вы должны использовать полное имя, чтобы достичь первоначального дескриптор свойства на родительском классе.

Демонстрация:

>>> class superhuman(human): 
...  @human.name.getter 
...  def name(self): 
...   return 'super ' + self._name 
... 
>>> s = superhuman('john') 
>>> print s.name 
super john 
>>> s.name = 'jack' 
>>> print s.name 
super jack 

Объект property дескриптора просто один объект, даже если он может иметь несколько методов, связанных с ней (геттер, инкубационного и DeleteR). Функции декоратора .getter, .setter и .deleter, предоставленные существующим дескриптором property, возвращают копию самого дескриптора с заменой одного конкретного метода.

Так что в вашем human базовом классе, что происходит, что вы первый создать дескриптор с @property декоратора, а затем заменить этот дескриптор с той, которая имеет как геттер и сеттер с синтаксисом . Это работает, потому что декораторы python заменяют оригинальную украшенную функцию с тем же именем, она в основном выполняет name = name.setter(name). См. How does the @property decorator work? для получения подробной информации о том, как все это работает.

В вашем подклассе вы просто используете этот трюк, чтобы создать новую копию дескриптора с замененным геттером.