Я хотел бы понять, как работает встроенная функция property
. Что меня смущает, так это то, что он property
также может быть использован в качестве декоратора, но он принимает аргументы только тогда, когда используется как встроенная функция, а не как декоратор.
Этот пример из документации :
class C(object):
def __init__(self):
self._x = None
def getx(self):
return self._x
def setx(self, value):
self._x = value
def delx(self):
del self._x
x = property(getx, setx, delx, "I'm the 'x' property.")
property
аргументы «S являются getx
, setx
, delx
и строка документации.
В приведенном ниже коде property
используется в качестве декоратора. Объектом этого является x
функция, но в приведенном выше коде нет места для объектной функции в аргументах.
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
И, как являются x.setter
и x.deleter
декораторы создали? Я запутался.
property
на самом деле это класс (не функция), хотя__init__()
, конечно, он вызывает метод, когда вы создаете объект. Использованиеhelp(property)
из терминала является проницательным.help
это также класс по какой-то причине.Ответы:
property()
Функция возвращает специальный объект дескриптора :Именно этот объект имеет дополнительные методы:
Они действуют как декораторы тоже . Они возвращают новый объект свойства:
это копия старого объекта, но с заменой одной из функций.
Помните, что
@decorator
синтаксис - это просто синтаксический сахар; синтаксис:на самом деле означает то же самое, что и
поэтому
foo
функция заменяется на тоproperty(foo)
, что мы видели выше, это специальный объект. Затем, когда вы используете@foo.setter()
, вы вызываетеproperty().setter
метод, который я показал вам выше, который возвращает новую копию свойства, но на этот раз с функцией setter, замененной декорированным методом.Следующая последовательность также создает свойство full-on, используя эти методы декоратора.
Сначала мы создаем некоторые функции и
property
объект с помощью всего лишь геттера:Далее мы используем
.setter()
метод для добавления сеттера:Наконец, мы добавляем удалитель с помощью
.deleter()
метода:И последнее , но не менее важное ,
property
объект действует как объект дескриптора , поэтому он имеет.__get__()
,.__set__()
и.__delete__()
методы , чтобы вклиниться в атрибут экземпляра получения, установки и удаления:Дескриптор Howto включает в себя чистый Python пример реализации этого
property()
типа:источник
Foo.prop = prop
вы можете сделатьFoo().prop = 5; pront Foo().prop; del Foo().prop
с желаемым результатом.type()
для доступа к атрибутам dunder, а методы предназначены для использования в качестве точек расширения стандартными функциями и операторами.@human.name.getter
изменитьproperty
объект на месте, а не вернуть новый,human.name
атрибут будет изменен, изменяя поведение этого суперкласса.Документация говорит, что это просто ярлык для создания свойств только для чтения. Так
эквивалентно
источник
@property
в качестве декоратора в своем классе.Вот минимальный пример того, как
@property
можно реализовать:В противном случае
word
остается метод вместо свойства.источник
self.word = my_word
- который тогда работал бы так жеprint( Thing('ok').word ) = 'ok'
Thing('ok').word
вызывает функцию внутри во время выполнения?Первая часть проста:
такой же как
property
с использованием только геттера.Следующим шагом будет расширение этого свойства установщиком и удалителем. И это происходит с соответствующими методами:
возвращает новое свойство, которое наследует все от старого
x
плюс заданный установщик.x.deleter
работает так же.источник
Это следующее:
Такой же как:
Такой же как:
Такой же как:
Который так же, как:
источник
Ниже приведен еще один пример того, как
@property
можно помочь, когда нужно провести рефакторинг кода, который взят отсюда (я только кратко излагаю его ниже):Представьте, что вы создали такой класс
Money
:и пользователь создает библиотеку в зависимости от этого класса, где он / она использует, например
Теперь предположим, что вы решили изменить свой
Money
класс и избавиться от атрибутовdollars
and,cents
но вместо этого решили отслеживать только общее количество центов:Если вышеупомянутый пользователь теперь пытается запустить свою библиотеку, как и раньше
это приведет к ошибке
Это означает, что теперь каждый, кто полагается на ваш оригинальный
Money
класс, должен будет изменить все строки кода, гдеdollars
иcents
используются, что может быть очень болезненным ... Итак, как этого можно избежать? Используя@property
!Вот как:
когда мы сейчас звоним из нашей библиотеки
все будет работать как положено, и нам не нужно было менять ни одной строки кода в нашей библиотеке! На самом деле, нам даже не нужно знать, что библиотека, от которой мы зависим, изменилась.
Также
setter
отлично работает:Вы можете использовать
@property
также в абстрактных классах; Я даю минимальный пример здесь .источник
self.dollar = dollars
? мы так много сделали с @property, но, похоже, функции извлечения не добавляются.Я прочитал все посты здесь и понял, что нам может понадобиться реальный пример из жизни. Почему, собственно, у нас есть @property? Итак, рассмотрим приложение Flask, в котором вы используете систему аутентификации. Вы объявляете модель пользователя в
models.py
:В этом коде у нас есть «скрытый» атрибут,
password
с помощью@property
которого запускаетсяAttributeError
утверждение при попытке прямого доступа к нему, в то время как мы использовали @ property.setter для установки фактической переменной экземпляраpassword_hash
.Теперь
auth/views.py
мы можем создать пользователя с:Атрибут уведомления,
password
который приходит из регистрационной формы, когда пользователь заполняет форму. Подтверждение пароля происходит в интерфейсе пользователяEqualTo('password', message='Passwords must match')
(в случае, если вам интересно, но это другая тема, связанная с колбами).Надеюсь этот пример будет полезен
источник
Эта точка зрения была прояснена многими людьми там, но вот прямая точка, которую я искал. Вот что я считаю важным начать с декоратора @property. например:-
Вызов функции "get_config ()" будет работать следующим образом.
Если вы заметили, я не использовал скобки "()" для вызова функции. Это основная вещь, которую я искал для @property Decorator. Так что вы можете использовать свою функцию как переменную.
источник
Начнем с Python-декораторов.
Декоратор Python - это функция, которая помогает добавить некоторые дополнительные функции к уже определенной функции.
В Python все является объектом. Функции в Python являются объектами первого класса, что означает, что на них можно ссылаться с помощью переменной, добавлять в списки, передавать в качестве аргументов другой функции и т. Д.
Рассмотрим следующий фрагмент кода.
Здесь мы можем сказать, что функция decorator изменила нашу функцию say_hello и добавила в нее несколько дополнительных строк кода.
Синтаксис Python для декоратора
Завершим все, чем с кейсом, но перед этим поговорим о некоторых людях.
Методы получения и установки используются во многих объектно-ориентированных языках программирования для обеспечения принципа инкапсуляции данных (рассматривается как связывание данных с методами, которые работают с этими данными).
Эти методы, конечно, являются средством получения данных и средством изменения данных.
Согласно этому принципу атрибуты класса делаются закрытыми, чтобы скрыть их и защитить от другого кода.
Да, @property - это в основном питонический способ использования геттеров и сеттеров.
У Python есть отличная концепция, называемая свойством, которая значительно упрощает жизнь объектно-ориентированного программиста.
Допустим, вы решили создать класс, который мог бы хранить температуру в градусах Цельсия.
Перефразированный код, вот как мы могли бы добиться этого с помощью собственности.
В Python property () - это встроенная функция, которая создает и возвращает объект свойства.
У объекта свойства есть три метода: getter (), setter () и delete ().
Вот,
мог быть разбит как,
Указать на примечание:
Теперь вы можете получить доступ к значению температуры, написав.
Кроме того, мы можем продолжить и не определять имена get_teuration и set_tempera, поскольку они не нужны и загрязняют пространство имен класса.
Вещий способ справиться с указанной выше проблемы является использование @property .
Указывает на Примечание -
Как видите, код определенно менее элегантен.
Теперь давайте поговорим об одном реальном практическом сценарии.
Допустим, вы разработали класс следующим образом:
Теперь давайте предположим, что наш класс стал популярным среди клиентов, и они начали использовать его в своих программах. Они делали все виды назначений для объекта.
И в один роковой день к нам пришел доверенный клиент и предположил, что значение «х» должно быть в диапазоне от 0 до 1000, это действительно ужасный сценарий!
Благодаря свойствам это легко: мы создаем версию свойства "x".
Это здорово, не правда ли: вы можете начать с самой простой реализации, какой только можно себе представить, и вы можете позже перейти на версию свойства без необходимости менять интерфейс! Так что свойства - это не просто замена геттерам и сеттерам!
Вы можете проверить эту реализацию здесь
источник
property
это класс за@property
декоратором.Вы всегда можете проверить это:
Я переписал пример с,
help(property)
чтобы показать, что@property
синтаксисфункционально идентичен
property()
синтаксису:Нет никакой разницы в том, как мы используем собственность, как вы можете видеть.
Для ответа на вопрос
@property
декоратор реализован черезproperty
класс.Итак, вопрос в том,
property
чтобы немного объяснить класс. Эта строка:Была инициализация. Мы можем переписать это так:
Смысл
fget
,fset
иfdel
:Следующее изображение показывает тройки, которые мы имеем, из класса
property
:__get__
,__set__
И__delete__
там быть переопределены . Это реализация шаблона дескриптора в Python.Мы также можем использовать свойство
setter
,getter
иdeleter
методы , чтобы связать функцию собственности. Проверьте следующий пример. Методs2
классаC
установит свойство в два раза .источник
Свойство может быть объявлено двумя способами.
Вы можете взглянуть на несколько примеров, которые я написал о свойствах в Python .
источник
Лучшее объяснение можно найти здесь: Python @Property Explained - Как использовать и когда? (Полные примеры) Сельва Прабхакаран | Опубликовано 5 ноября 2018
Это помогло мне понять, ПОЧЕМУ не только КАК.
https://www.machinelearningplus.com/python/python-property/
источник
Вот еще один пример:
По сути, так же, как в примере с C (object), за исключением того, что я использую вместо него x ... Я также не инициализирую в __init - ... хорошо .. Я делаю, но его можно удалить, потому что __x определяется как часть класса ....
Выход:
и если я закомментирую self.x = 1234 в init, то получится :
и если я установлю _default = None на _default = 0 в функции получателя (поскольку все получатели должны иметь значение по умолчанию, но оно не передается значениями свойств из того, что я видел, так что вы можете определить его здесь, и на самом деле это неплохо, потому что вы можете определить значение по умолчанию один раз и использовать его везде) т.е.: def x (self, _default = 0):
Примечание: логика getter просто для того, чтобы значение им манипулировало, чтобы оно им манипулировало - то же самое для операторов print ...
Примечание: я привык к Lua и могу динамически создавать более 10 помощников, когда я вызываю одну функцию, и я сделал что-то похожее для Python без использования свойств, и это работает до некоторой степени, но, хотя функции создаются раньше будучи использованным, иногда возникают проблемы с вызовом их до создания, что странно, поскольку это не кодируется таким образом ... Я предпочитаю гибкость мета-таблиц Lua и тот факт, что я могу использовать фактические установщики / получатели вместо того, чтобы напрямую обращаться к переменной ... Мне нравится, как быстро некоторые вещи могут быть созданы с помощью Python - например, программы с графическим интерфейсом. хотя тот, который я проектирую, может быть невозможен без большого количества дополнительных библиотек - если я кодирую его в AutoHotkey, я могу получить прямой доступ к нужным мне вызовам dll, и то же самое можно сделать в Java, C #, C ++,
Примечание. Вывод кода на этом форуме не работает - мне пришлось добавить пробелы в первую часть кода, чтобы он работал - при копировании / вставке убедитесь, что вы преобразуете все пробелы во вкладки .... Я использую вкладки для Python, потому что в размер файла, который составляет 10 000 строк, может составлять от 512 КБ до 1 МБ с пробелами и от 100 до 200 КБ со вкладками, что соответствует огромной разнице в размере файла и сокращению времени обработки ...
Вкладки также могут быть настроены для каждого пользователя - так что если вы предпочитаете ширину в 2 пробела, 4, 8 или что-то еще, что вы можете сделать, это означает, что это полезно для разработчиков с недостатком зрения.
Примечание: все функции, определенные в классе, не имеют правильного отступа из-за ошибки в программном обеспечении форума - убедитесь, что вы сделали отступ, если копируете / вставляете
источник
Одно замечание: для меня, для Python 2.x,
@property
не работал как рекламируется, когда я не наследовал отobject
:но работал когда:
для Python 3 работал всегда.
источник
object
является классом старого стиля, а классы старого стиля не поддерживают протокол дескриптора (которыйproperty
реализуется так, как он работает). В Python 3 классы старого стиля больше не существуют; все классы - это то, что мы называли классами нового стиля в Python 2.