Python переопределяет геттер без сеттера

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

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

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

Ответ 1

Используйте только декоратор .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 - это всего лишь один объект, хотя он может иметь несколько связанных с ним методов (getter, setter и deleter). Функции декоратора .getter, .setter и .deleter, предоставляемые существующим дескриптором property, возвращают копию самого дескриптора с заменой одного конкретного метода.

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

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