Почему для свойств Python требуются вспомогательные функции с одинаковыми именами?

В документах, объясняющих свойства, сказано:

Обязательно присвойте дополнительным функциям то же имя, что и у исходного свойства (в данном случае x).

То есть, методы getter, setter и deleter должны иметь одинаковое имя.

Зачем? А также, Python запрещает перегрузку методов, не так ли?

РЕДАКТИРОВАТЬ: Почему следующий код не работает при запуске в Python 2.6?

class Widget(object):
    def __init__(self, thing):
        self.thing = thing
        print self.thing

    @property
    def thing(self):
        return self._thing

    @thing.setter
    def set_thing(self, value):
        self._thing = value


if __name__ == '__main__':
    Widget('Some nonsense here')  

Его вывод:

 Traceback (most recent call last):   
 File "widget.py", line 16, in <module>
     Widget('Some nonsense here')     
 File "widget.py", line 3, in __init__
     self.thing = thing 
 AttributeError: can't set attribute

Код работает нормально, когда set_thing() переименован в thing().

2 ответа

Решение

В Python действительно нет функции перегрузки методов, но вы правы в том, что документы побуждают вас одинаково называть методы получения и установки и демонстрируют его загрузку. Что тут происходит?

Хитрость заключается в том, чтобы понять, как декораторы методов работают в Python. Всякий раз, когда вы видите что-то вроде этого:

@foo
def bar():
    frob()
    quux()

что Python на самом деле делает под прикрытием, так это переписать его так:

def bar():
    frob()
    quux()
bar = foo(bar)

Другими словами: определить функцию bar, затем замените его на результат вызова foo на функции бара.

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

def __secret_internal_function_name__():
    frob()
    quux()
bar = foo(__secret_internal_function_name__)

Почему это важно? Давайте посмотрим на Python в этой ссылке на документацию:

class C(object):
    def __init__(self):
        self._x = None

    @property
    def x(self):
        """I'm the 'x' property."""
        return self._x

    @x.setter
    def x(self, value):
        self._x = value

    @x.deleter
    def x(self):
        del self._x

Давайте перепишем это, используя то, что мы теперь знаем, чтобы понять, что на самом деле делает Python:

class C(object):
    def __init__(self):
        self._x = None

    def __secret_x_prop__(self):
        """I'm the 'x' property."""
        return self._x
    x = property(__secret_x_prop__)

    def __secret_x_setter__(self, value):
        self._x = value
    x = x.setter(__secret_x_setter__)

    def __secret_x_getter__(self):
        del self._x
    x = x.deleter(__secret_x_getter__)

Теперь мы можем увидеть, что происходит: мы не перегружаем функции; мы постепенно строим property объект, который ссылается на другие функции.

Также стоит отметить, что в зависимости от того, как вы создаете свойство, имена не обязательно должны совпадать. В частности, если вы создаете свойство явно с property функция, как это делается в первом примере в документации, имена могут быть любыми; в примере их называют getx, setx, а также delx и работает нормально. В том, что я предполагаю, это мера предосторожности, property.setter, property.deleter и тому подобное требуют, чтобы переданная функция имела то же имя, но они делают то же самое за кулисами, что и более явные property пример.

В документах, объясняющих свойства, сказано:

Неправильно. Это документация, объясняющая использование имени свойства как части декоратора. При создании свойств "классическим" способом методы могут иметь любое имя.

И поскольку декоратор перехватывает создание метода, перегрузка отсутствует.

Другие вопросы по тегам