Вы хотите использовать декоратор, всегда. нет никакого преимущества для другого синтаксиса и есть только недостатки.
Точка декораторов
Это потому, что синтаксис декоратора был придуман специально для избежать другой синтаксис.Любые примеры разнообразия name = property(...)
обычно содержатся в коде, предшествующем декораторам.
Синтаксис декоратора: синтаксический сахар ;форма
@decorator
def functionname(...):
# ...
выполняется так же, как
def functionname(...):
# ...
functionname = decorator(functionname)
без присваивания functionname
дважды (часть def functionname(...)
создает функциональный объект и обычно присваивает functionname
, но с декоратором объект функции создается и передается непосредственно объекту декоратора.)
Python добавил эту функцию, потому что, когда тело вашей функции имеет длину long , вы не можете легко увидеть этофункция была обёрнута декоратором.Вам нужно прокрутить вниз определение функции, чтобы увидеть это, и это не очень полезно, когда почти все остальное , которое вы хотите знать о функции, находится прямо вверху;Аргументы, имя, строка документа прямо здесь.
Из оригинального PEP 318 - Декораторы для функций и методов Спецификация:
Текущий метод применения преобразования к функции или методу размещает фактическое преобразование после тела функции.Для больших функций это отделяет ключевой компонент поведения функции от определения остальной части внешнего интерфейса функции.
[...]
Это становится менее читабельным при использовании более длинных методов.Кроме того, кажется неуместным назвать функцию трижды для того, что концептуально является единым объявлением.
и под Цели проектирования :
новый синтаксис должен
- [...]
- переместиться от конца функции, где он в данный момент скрыт, к передней части, где оно больше на вашем лице
Таким образом, использование
@property
def latitude(self):
# ...
@latitude.setter
def latitude(self, latitude):
# ...
гораздо более читабельно и самодокументируется , чем
def get_latitude(self):
# ...
def set_latitude(self, latitude):
# ...
latitude = property(get_latitude, set_latitude)
Нет загрязнения пространства имен
Далее, поскольку декоратор @property
заменяет декорируемый вами функциональный объект результатом декорации (экземпляр property
), вы также избегаете загрязнения пространства имен .Без @property
и @<name>.setter
и @<name>.deleter
вы должны добавить 3 дополнительных, отдельных имени к определению вашего класса, которое никто и никогда не будет использовать:
>>> [n for n in sorted(vars(Location)) if n[:2] != '__']
['get_latitude', 'get_longitude', 'latitude', 'longitude', 'set_latitude', 'set_longitude']
Представьте себе класс с 5, 10 или даже более определениями свойств.Разработчики, менее знакомые с проектом и автозаполняющейся средой IDE, наверняка будут смущены разницей между get_latitude
, latitude
и set_latitude
, и вы в конечном итоге получите код, который смешивает стили и затрудняет теперь отход отПредоставление этих методов на уровне класса.
Конечно, вы можете использовать del get_latitude, set_latitude
сразу после назначения latitude = property(...)
, но это еще более дополнительный код для выполнения без реальной цели.
Запутываетимена методов
Несмотря на то, что вы можете избежать префикса имен доступа с помощью get_
и set_
или иным образом различать имена, чтобы создать из них объект property()
, это все равно, как почти весь код, который не делаетиспользование синтаксиса декоратора @property
приводит к именованию методов доступа.
И это может привести к некоторой путанице в трассировках;исключение, возникшее в одном из методов доступа, приводит к трассировке с get_latitude
или set_latitude
в имени, в то время как в предыдущей строке использовалось object.latitude
.Новичку в свойствах Python может быть не всегда понятно, как они связаны, особенно если они пропустили линию latitude = property(...)
дальше;см. выше.
Доступ к методам доступа, как наследовать
Вы можете указать, что вам в любом случае может понадобиться доступ к этим функциям;например, при переопределении только метода получения или установки свойства в подклассе при наследовании другого метода доступа.
Но объект property
при доступе к классу уже дает вам ссылки на средства доступа через атрибуты .fget
, .fset
и .fdel
:
>>> Location.latitude
<property object at 0x10d1c3d18>
>>> Location.latitude.fget
<function Location.get_latitude at 0x10d1c4488>
>>> Location.latitude.fset
<function Location.set_latitude at 0x10d195ea0>
и вы можете повторно использовать синтаксис @<name>.getter
/ @<name>.setter
/ @<name>.deleter
в подклассе без необходимости создавать новый объект property
!
С помощьюстарый синтаксис, было обычным делом пытаться переопределить только один из методов доступа:
class SpecialLocation(Location):
def set_latitude(self, latitude):
# ...
и затем удивляться, почему он не будет подхвачен унаследованным объектом property
.
с помощьюСинтаксис декоратора, который вы будете использовать:
class SpecialLocation(Location):
@Location.latitude.setter
def latitude(self, latitude):
# ...
, а затем подклассу SpecialLocation
дается новый экземпляр property()
с получателем, унаследованным от Location
, и с новым установщиком.
TLDR
Использовать синтаксис декоратора.
- Самодокументируемый
- Избегает загрязнения пространства имен
- Делает наследование свойств от свойств более чистым и простым