Почему для свойств 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
пример.
В документах, объясняющих свойства, сказано:
Неправильно. Это документация, объясняющая использование имени свойства как части декоратора. При создании свойств "классическим" способом методы могут иметь любое имя.
И поскольку декоратор перехватывает создание метода, перегрузка отсутствует.