Як працює функція @ Properties decorator?

Я хотів би зрозуміти, як працює вбудована функція 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 arguments are getx, setx, delx and a doc string.

У наведеному нижче коді 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 ? Я збентежений.

670
додано Автор Martin Thoma, джерело
property насправді є класом (а не функцією), хоча, звичайно, він називає метод __ init __() під час створення об'єкта. Використання help (property) з терміналу є проникливим. help також є класом з якоїсь причини.
додано Автор Shule, джерело

11 Відповіді

Функція property() повертає спеціальний об'єкт дескриптора :

>>> property()

Цей об'єкт має методи extra :

>>> property().getter

>>> property().setter

>>> property().deleter

Вони діють як декоратори теж . Вони повертають новий об'єкт властивості:

>>> property().getter(None)

це копія старого об'єкта, але замість однієї з функцій.

Пам'ятайте, що синтаксис @decorator - це просто синтаксичний цукор; синтаксис:

@property
def foo(self): return self._foo

дійсно означає те ж саме, що і

def foo(self): return self._foo
foo = property(foo)

тому foo замінює функцію property (foo) , яку ми бачили вище, - це особливий об'єкт. Тоді, коли ви використовуєте @ foo.setter() , що ви робите, називайте метод property (). Setter , я показав вам вище, що повертає нову копію властивість, але на цей раз функція setter замінена декорованим методом.

Ця послідовність також створює повнофункціональну властивість, використовуючи ці методи декоратора.

Спочатку ми створюємо деякі функції та об'єкт property лише з getter:

>>> def getter(self): print 'Get!'
... 
>>> def setter(self, value): print 'Set to {!r}!'.format(value)
... 
>>> def deleter(self): print 'Delete!'
... 
>>> prop = property(getter)
>>> prop.fget is getter
True
>>> prop.fset is None
True
>>> prop.fdel is None
True

Далі ми використовуємо метод .setter() , щоб додати сеттера:

>>> prop = prop.setter(setter)
>>> prop.fget is getter
True
>>> prop.fset is setter
True
>>> prop.fdel is None
True

Нарешті, додати видалення методом .deleter() :

>>> prop = prop.deleter(deleter)
>>> prop.fget is getter
True
>>> prop.fset is setter
True
>>> prop.fdel is deleter
True

Нарешті, але не менш важливо, об'єкт property діє як об'єкт дескриптора , тому він має .__ get __ ( ) , .__ set __() та .__ видалити __() , щоб зафіксувати отримання, налаштування та видалення атрибуту instance:

>>> class Foo(object): pass
... 
>>> prop.__get__(Foo(), Foo)
Get!
>>> prop.__set__(Foo(), 'bar')
Set to 'bar'!
>>> prop.__delete__(Foo())
Delete!

Посібник дескриптора містить чистий приклад реалізації python властивості тип() :

  клас Властивість (об'єкт):
    "Емулювати PyProperty_Type() у об'єктах/descrobject.c"

    Def __init __ (self, fget = Ні, fset = Ні, fdel = Немає, doc = Немає):
        self.fget = fget
        self.fset = fset
        self.fdel = fdel
        якщо doc є None і fget не None
            doc = fget .__ doc__
        Сам .__ doc__ = Док

    Def __get __ (self, obj, objtype = None):
        якщо obj - ніхто
            Повернутися самостійно
        якщо self.fget немає:
            збільшити AttributeError ("нечитабельний атрибут")
        Повернутися self.fget (obj)

    Def __set __ (self, obj, value):
        якщо self.fset є None:
            підвищити AttributeError ("неможливо встановити атрибут")
        self.fset (obj, значення)

    Def __delete __ (self, obj):
        якщо self.fdel None
            збільшити AttributeError ("неможливо видалити атрибут")
        self.fdel (obj)

    дефрагментатор (сам, fget):
        Тип повернення (self) (fget, self.fset, self.fdel, self.__ doc__)

    дефектор (self, fset):
        return type (self) (self.fget, fset, self.fdel, self.__ doc__)

    Def Deleter (Я, Fdel):
        Тип повернення (self) (self.fget, self.fset, fdel, self .__ doc__)
 
748
додано
Чому property (). Getter та property (). Deleter мають однакову адресу, але property (). Setter ?
додано Автор gerrit, джерело
Чи правильно я, що @property getter працює для старих класів, але @ property.setter не працює?
додано Автор Mr_and_Mrs_D, джерело
Дуже добре. Ви можете додати той факт, що після Foo.prop = prop ви можете виконати Foo (). Prop = 5; pront foo (). prop; del Foo (). prop з бажаним результатом.
додано Автор glglgl, джерело
@MartijnPieters це помилка методу getter ? return type (self) (fget, self.fset, self.fdel, self.__ doc __) Я думаю, це має бути self.fget , а не тільки fget правильно? або є певна причина, чому саме так.
додано Автор Zion, джерело
right2x! Я отримую його зараз. також просто пояснення, як і раніше на метод getter , оскільки return type (self) (fget, self.fset, self.fdel, self .__ doc __) є в основному справедливим повернення класу прямо? і аргументи ключового слова вже виконуються за умовчанням в fset і fdel . чи може метод getter бути переписаний на лише return type (self) (fget) ? як fset , так і fdel вже мають значення none
додано Автор Zion, джерело
@MartijnPieters праворуч. ok2x Я повільно отримую це. Людина, ця людина, дуже думає. Я ціную час, який ви брали, щоб відповісти на мої запитання. спасибі
додано Автор Zion, джерело
@Zion: він повертає новий екземпляр класу, копіюючи через всі інші атрибути, замінюючи аргумент fget . Ви отримаєте новий екземпляр property , налаштований, щоб зробити те ж саме, що й старий, крім атрибута fget було замінено.
додано Автор Martijn Pieters, джерело
@Zion: так, ні, ти не можеш замінити його за допомогою типу (self (fget)) , тому тоді встановлювач, deleter і docstring будуть втрачені.
додано Автор Martijn Pieters, джерело
@Zion: ви, як правило, використовуєте @ existing_property.setter або @ existing_property.deleter як декоратори, але якщо ви підкласуєте щось з властивістю, де ви хочете переопределити getter, ви Використовуйте @ ParentClass.existing_property.getter як декоратор.
додано Автор Martijn Pieters, джерело
@Zion: він повинен не , код правильний. Ознайомте увагу з моєю відповіддю, де він пояснює, як працює декоратор @ existing_property.getter .
додано Автор Martijn Pieters, джерело
@AnttiHaapala: Мені може бути щось відсутнє, але який код у цьому питанні буде? Обидва фрагменти там будуть працювати однаково в Py2 і Py3!
додано Автор Martijn Pieters, джерело
@AnttiHaapala: Python 3 дескриптор HOWTO чудово застряє в світогляді Python 2 ; він все ще говорить про незв'язані методи. Жоден з прикладів у цьому документі не є специфічним для Python 3.
додано Автор Martijn Pieters, джерело
Об'єкти методу створюються на льоту, і можна повторно використовувати ту ж саму область пам'яті, якщо вона доступна.
додано Автор Martijn Pieters, джерело
@Mr_and_Mrs_D: так, лише класи нового стилю реалізують повний дескрипторний протокол, необхідний для властивостей. У старому стилі підтримується лише __ get __ .
додано Автор Martijn Pieters, джерело
@MarkusMeskanen: Я скоріше використовую type() як доступ до атрибутів dunder, і методи призначені для використання як розширення для стандартних функцій та операторів.
додано Автор Martijn Pieters, джерело
@MarkusMeskanen: тому що об'єкт незмінний, і якщо ви мутували його на місці, ви не могли його спеціалізувати в підкласі.
додано Автор Martijn Pieters, джерело
@MarkusMeskanen: дивіться Python, що переважає геттер без встановлення ; якщо @ human.name.getter змінює об'єкт property на місці, а не повертає новий, атрибут human.name буде змінений, змінюючи поведінку цього суперкласу.
додано Автор Martijn Pieters, джерело
Не ті, що в Python 3 howto: (old vs new-style classes).
додано Автор Antti Haapala, джерело
Я б дуже хотів послати на Python 3 HOWTO, але це теж дуже погано, питання включає в себе код, поведінка якого відрізнятиметься від Py2 vs Py3.
додано Автор Antti Haapala, джерело
@MartijnPieters Чому ми повертаємо новий екземпляр Property щоразу, коли ми називаємо getter() , setter() або deleter() , а не просто змінювати існуючий екземпляр ( self.fset = fset; return self )?
додано Автор Markus Meskanen, джерело
@MartijnPieters Чи можна надати мені приклад? Я не можу зрозуміти, чому б ви не могли його спеціалізувати в підкласі ...: /
додано Автор Markus Meskanen, джерело
Чи існує різниця між використанням типу (self) (self.fget, ...) і self .__ class __ (self.fget, ...) ? Для мене останній виглядає більш чистим, тому я хотів би використати це в своїх власних проектах, якщо це те ж саме.
додано Автор Markus Meskanen, джерело
@Zion Привіт reddit користувач. (Відповідь Мартіна була згадувана кілька разів на reddit , завдяки Мартіну від усіх нас, щоб навчати подібне!)
додано Автор Skamah One, джерело

Функція property() повертає спеціальний об'єкт дескриптора :

>>> property()

Цей об'єкт має методи extra :

>>> property().getter

>>> property().setter

>>> property().deleter

Вони діють як декоратори теж . Вони повертають новий об'єкт властивості:

>>> property().getter(None)

це копія старого об'єкта, але замість однієї з функцій.

Пам'ятайте, що синтаксис @decorator - це просто синтаксичний цукор; синтаксис:

@property
def foo(self): return self._foo

дійсно означає те ж саме, що і

def foo(self): return self._foo
foo = property(foo)

тому foo замінює функцію property (foo) , яку ми бачили вище, - це особливий об'єкт. Тоді, коли ви використовуєте @ foo.setter() , що ви робите, називайте метод property (). Setter , я показав вам вище, що повертає нову копію властивість, але на цей раз функція setter замінена декорованим методом.

Ця послідовність також створює повнофункціональну властивість, використовуючи ці методи декоратора.

Спочатку ми створюємо деякі функції та об'єкт property лише з getter:

>>> def getter(self): print 'Get!'
... 
>>> def setter(self, value): print 'Set to {!r}!'.format(value)
... 
>>> def deleter(self): print 'Delete!'
... 
>>> prop = property(getter)
>>> prop.fget is getter
True
>>> prop.fset is None
True
>>> prop.fdel is None
True

Далі ми використовуємо метод .setter() , щоб додати сеттера:

>>> prop = prop.setter(setter)
>>> prop.fget is getter
True
>>> prop.fset is setter
True
>>> prop.fdel is None
True

Нарешті, додати видалення методом .deleter() :

>>> prop = prop.deleter(deleter)
>>> prop.fget is getter
True
>>> prop.fset is setter
True
>>> prop.fdel is deleter
True

Нарешті, але не менш важливо, об'єкт property діє як об'єкт дескриптора , тому він має .__ get __ ( ) , .__ set __() та .__ видалити __() , щоб зафіксувати отримання, налаштування та видалення атрибуту instance:

>>> class Foo(object): pass
... 
>>> prop.__get__(Foo(), Foo)
Get!
>>> prop.__set__(Foo(), 'bar')
Set to 'bar'!
>>> prop.__delete__(Foo())
Delete!

Посібник дескриптора містить чистий приклад реалізації python властивості тип() :

  клас Властивість (об'єкт):
    "Емулювати PyProperty_Type() у об'єктах/descrobject.c"

    Def __init __ (self, fget = Ні, fset = Ні, fdel = Немає, doc = Немає):
        self.fget = fget
        self.fset = fset
        self.fdel = fdel
        якщо doc є None і fget не None
            doc = fget .__ doc__
        Сам .__ doc__ = Док

    Def __get __ (self, obj, objtype = None):
        якщо obj - ніхто
            Повернутися самостійно
        якщо self.fget немає:
            збільшити AttributeError ("нечитабельний атрибут")
        Повернутися self.fget (obj)

    Def __set __ (self, obj, value):
        якщо self.fset є None:
            підвищити AttributeError ("неможливо встановити атрибут")
        self.fset (obj, значення)

    Def __delete __ (self, obj):
        якщо self.fdel None
            збільшити AttributeError ("неможливо видалити атрибут")
        self.fdel (obj)

    дефрагментатор (сам, fget):
        Тип повернення (self) (fget, self.fset, self.fdel, self.__ doc__)

    дефектор (self, fset):
        return type (self) (self.fget, fset, self.fdel, self.__ doc__)

    Def Deleter (Я, Fdel):
        Тип повернення (self) (self.fget, self.fset, fdel, self .__ doc__)
 
748
додано
Чому property (). Getter та property (). Deleter мають однакову адресу, але property (). Setter ?
додано Автор gerrit, джерело
Чи правильно я, що @property getter працює для старих класів, але @ property.setter не працює?
додано Автор Mr_and_Mrs_D, джерело
Дуже добре. Ви можете додати той факт, що після Foo.prop = prop ви можете виконати Foo (). Prop = 5; pront foo (). prop; del Foo (). prop з бажаним результатом.
додано Автор glglgl, джерело
@MartijnPieters це помилка методу getter ? return type (self) (fget, self.fset, self.fdel, self.__ doc __) Я думаю, це має бути self.fget , а не тільки fget правильно? або є певна причина, чому саме так.
додано Автор Zion, джерело
right2x! Я отримую його зараз. також просто пояснення, як і раніше на метод getter , оскільки return type (self) (fget, self.fset, self.fdel, self .__ doc __) є в основному справедливим повернення класу прямо? і аргументи ключового слова вже виконуються за умовчанням в fset і fdel . чи може метод getter бути переписаний на лише return type (self) (fget) ? як fset , так і fdel вже мають значення none
додано Автор Zion, джерело
@MartijnPieters праворуч. ok2x Я повільно отримую це. Людина, ця людина, дуже думає. Я ціную час, який ви брали, щоб відповісти на мої запитання. спасибі
додано Автор Zion, джерело
@Zion: так, ні, ти не можеш замінити його за допомогою типу (self (fget)) , тому тоді встановлювач, deleter і docstring будуть втрачені.
додано Автор Martijn Pieters, джерело
@Zion: він повертає новий екземпляр класу, копіюючи через всі інші атрибути, замінюючи аргумент fget . Ви отримаєте новий екземпляр property , налаштований, щоб зробити те ж саме, що й старий, крім атрибута fget було замінено.
додано Автор Martijn Pieters, джерело
@Zion: ви, як правило, використовуєте @ existing_property.setter або @ existing_property.deleter як декоратори, але якщо ви підкласуєте щось з властивістю, де ви хочете переопределити getter, ви Використовуйте @ ParentClass.existing_property.getter як декоратор.
додано Автор Martijn Pieters, джерело
@Zion: він повинен не , код правильний. Ознайомте увагу з моєю відповіддю, де він пояснює, як працює декоратор @ existing_property.getter .
додано Автор Martijn Pieters, джерело
@AnttiHaapala: Мені може бути щось відсутнє, але який код у цьому питанні буде? Обидва фрагменти там будуть працювати однаково в Py2 і Py3!
додано Автор Martijn Pieters, джерело
@AnttiHaapala: Python 3 дескриптор HOWTO чудово застряє в світогляді Python 2 ; він все ще говорить про незв'язані методи. Жоден з прикладів у цьому документі не є специфічним для Python 3.
додано Автор Martijn Pieters, джерело
@MarkusMeskanen: Я скоріше використовую type() як доступ до атрибутів dunder, і методи призначені для використання як розширення для стандартних функцій та операторів.
додано Автор Martijn Pieters, джерело
Об'єкти методу створюються на льоту, і можна повторно використовувати ту ж саму область пам'яті, якщо вона доступна.
додано Автор Martijn Pieters, джерело
@MarkusMeskanen: тому що об'єкт незмінний, і якщо ви мутували його на місці, ви не могли його спеціалізувати в підкласі.
додано Автор Martijn Pieters, джерело
@MarkusMeskanen: дивіться Python, що переважає геттер без встановлення ; якщо @ human.name.getter змінює об'єкт property на місці, а не повертає новий, атрибут human.name буде змінений, змінюючи поведінку цього суперкласу.
додано Автор Martijn Pieters, джерело
@Mr_and_Mrs_D: так, лише класи нового стилю реалізують повний дескрипторний протокол, необхідний для властивостей. У старому стилі підтримується лише __ get __ .
додано Автор Martijn Pieters, джерело
Не ті, що в Python 3 howto: (old vs new-style classes).
додано Автор Antti Haapala, джерело
Я б дуже хотів послати на Python 3 HOWTO, але це теж дуже погано, питання включає в себе код, поведінка якого відрізнятиметься від Py2 vs Py3.
додано Автор Antti Haapala, джерело
@MartijnPieters Чи можна надати мені приклад? Я не можу зрозуміти, чому б ви не могли його спеціалізувати в підкласі ...: /
додано Автор Markus Meskanen, джерело
@MartijnPieters Чому ми повертаємо новий екземпляр Property щоразу, коли ми називаємо getter() , setter() або deleter() , а не просто змінювати існуючий екземпляр ( self.fset = fset; return self )?
додано Автор Markus Meskanen, джерело
Чи існує різниця між використанням типу (self) (self.fget, ...) і self .__ class __ (self.fget, ...) ? Для мене останній виглядає більш чистим, тому я хотів би використати це в своїх власних проектах, якщо це те ж саме.
додано Автор Markus Meskanen, джерело
@Zion Привіт reddit користувач. (Відповідь Мартіна була згадувана кілька разів на reddit , завдяки Мартіну від усіх нас, щоб навчати подібне!)
додано Автор Skamah One, джерело

Documentation says it's just a shortcut for creating readonly properties. So

@property
def x(self):
    return self._x

еквівалентно

def getx(self):
    return self._x
x = property(getx)
103
додано

Documentation says it's just a shortcut for creating readonly properties. So

@property
def x(self):
    return self._x

еквівалентно

def getx(self):
    return self._x
x = property(getx)
103
додано

Перша частина проста:

@property
def x(self): ...

такий же, як і

def x(self): ...
x = property(x)
  • , що, у свою чергу, є спрощеним синтаксисом для створення property з лише одержувачем.

Наступним кроком буде розширення цього властивості за допомогою setter і deleter. І це відбувається з відповідними методами:

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

повертає нову властивість, яка успадковує все від старого x плюс заданий сеттер.

x.deleter works the same way.

63
додано

Перша частина проста:

@property
def x(self): ...

такий же, як і

def x(self): ...
x = property(x)
  • , що, у свою чергу, є спрощеним синтаксисом для створення property з лише одержувачем.

Наступним кроком буде розширення цього властивості за допомогою setter і deleter. І це відбувається з відповідними методами:

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

повертає нову властивість, яка успадковує все від старого x плюс заданий сеттер.

x.deleter works the same way.

63
додано

Ось приклад мінімального способу реалізації @property :

class Thing:
    def __init__(self, my_word):
        self._word = my_word 
    @property
    def word(self):
        return self._word

>>> print( Thing('ok').word )
'ok'

Інакше word залишається методом замість властивості.

class Thing:
    def __init__(self, my_word):
        self._word = my_word
    def word(self):
        return self._word

>>> print( Thing('ok').word() )
'ok'
51
додано
Краща ілюстрація, яку я коли-небудь читав.
додано Автор JawSaw, джерело
Як би цей приклад виглядав, якщо функція/властивість слова() потрібна для визначення init ?
додано Автор J.J, джерело
@SilverSlash Це просто приклад, реальний варіант використання буде містити більш складний метод
додано Автор AlexG, джерело
Чи може хтось пояснити, чому я тут створив декоратор властивостей, а не просто self.word = my_word - який потім працюватиме так само print (Thing ('ok'). word) = "добре"
додано Автор SilverSlash, джерело
Дуже добре. Читаючи інші відповіді і переживаючи ваш приклад, я, нарешті, це розумію. Дякую за це!
додано Автор Arun Das, джерело

Це наступне:

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

Такий же, як:

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

    def _x_get(self):
        return self._x

    def _x_set(self, value):
        self._x = value

    def _x_del(self):
        del self._x

    x = property(_x_get, _x_set, _x_del, 
                    "I'm the 'x' property.")

Такий же, як:

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

    def _x_get(self):
        return self._x

    def _x_set(self, value):
        self._x = value

    def _x_del(self):
        del self._x

    x = property(_x_get, doc="I'm the 'x' property.")
    x = x.setter(_x_set)
    x = x.deleter(_x_del)

Такий же, як:

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

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

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

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

Що таке саме, як:

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
25
додано

Я прочитав всі записи тут і зрозумів, що нам може знадобитися реальний приклад життя. Чому, насправді, ми маємо @ власність? Отже, розгляньте додаток Flask, де використовується система автентифікації. Ви оголошуєте користувачем моделі в models.py :

class User(UserMixin, db.Model):
    __tablename__ = 'users'
    id = db.Column(db.Integer, primary_key=True)
    email = db.Column(db.String(64), unique=True, index=True)
    username = db.Column(db.String(64), unique=True, index=True)
    password_hash = db.Column(db.String(128))

    ...

    @property
    def password(self):
        raise AttributeError('password is not a readable attribute')

    @password.setter
    def password(self, password):
        self.password_hash = generate_password_hash(password)

    def verify_password(self, password):
        return check_password_hash(self.password_hash, password)

У цьому коді ми маємо "прихований" атрибут password , використовуючи @property , який запускає твердження AttributeError , коли ви намагаєтеся отримати доступ до нього безпосередньо, поки ми used @ property.setter для встановлення фактичної змінної password_hash .

Тепер у auth/views.py ми можемо спробувати користувача з:

...
@auth.route('/register', methods=['GET', 'POST'])
def register():
    form = RegisterForm()
    if form.validate_on_submit():
        user = User(email=form.email.data,
                    username=form.username.data,
                    password=form.password.data)
        db.session.add(user)
        db.session.commit()
...

Зверніть увагу на атрибут password , який походить від реєстраційної форми, коли користувач заповнює форму. Підтвердження пароля відбувається на передній панелі за допомогою EqualTo ('password', message = 'Паролі повинні збігатися') (у випадку, якщо вам цікаво, але це різні теми, пов'язані з Фляжкою).

Я сподіваюсь, що цей приклад буде корисним

5
додано

Ось ще один приклад:

##
## Python Properties Example
##
class GetterSetterExample( object ):
    ## Set the default value for x ( we reference it using self.x, set a value using self.x = value )
    __x = None


##
## On Class Initialization - do something... if we want..
##
def __init__( self ):
    ## Set a value to __x through the getter/setter... Since __x is defined above, this doesn't need to be set...
    self.x = 1234

    return None


##
## Define x as a property, ie a getter - All getters should have a default value arg, so I added it - it will not be passed in when setting a value, so you need to set the default here so it will be used..
##
@property
def x( self, _default = None ):
    ## I added an optional default value argument as all getters should have this - set it to the default value you want to return...
    _value = ( self.__x, _default )[ self.__x == None ]

    ## Debugging - so you can see the order the calls are made...
    print( '[ Test Class ] Get x = ' + str( _value ) )

    ## Return the value - we are a getter afterall...
    return _value


##
## Define the setter function for x...
##
@x.setter
def x( self, _value = None ):
    ## Debugging - so you can see the order the calls are made...
    print( '[ Test Class ] Set x = ' + str( _value ) )

    ## This is to show the setter function works.... If the value is above 0, set it to a negative value... otherwise keep it as is ( 0 is the only non-negative number, it can't be negative or positive anyway )
    if ( _value > 0 ):
        self.__x = -_value
    else:
        self.__x = _value


##
## Define the deleter function for x...
##
@x.deleter
def x( self ):
    ## Unload the assignment/data for x
    if ( self.__x != None ):
        del self.__x


##
## To String/Output Function for the class - this will show the property value for each property we add...
##
def __str__( self ):
    ## Output the x property data...
    print( '[ x ] ' + str( self.x ) )


    ## Return a new line - technically we should return a string so it can be printed where we want it, instead of printed early if _data = str( C( ) ) is used....
    return '\n'

##
##
##
_test = GetterSetterExample( )
print( _test )

## For some reason the deleter isn't being called...
del _test.x

В основному те ж саме, що і приклад C (об'єкта), за винятком, що я використовую x ... Я також не ініціалізуюся в __init - ... добре ... я, але це може бути видалено, оскільки __x визначається як частина класу ....

Вихід:

[ Test Class ] Set x = 1234
[ Test Class ] Get x = -1234
[ x ] -1234

and if I comment out the self.x = 1234 in init then Вихід:

[ Test Class ] Get x = None
[ x ] None

і якщо я встановлюю _default = None до _default = 0 в функції getter (оскільки всі getter повинні мати значення за замовчуванням, але це не передано значенням властивостей з того, що я бачив, щоб ви могли це визначити тут, і це насправді не погано, тому що ви можете одночасно визначити за замовчуванням і використовувати його скрізь), тобто: def x (self, _default = 0):

[ Test Class ] Get x = 0
[ x ] 0

Примітка: логіка getter полягає лише в тому, щоб маніпулювати значенням це значення, щоб забезпечити його маніпуляцію - те ж саме для операторів друку ...

Примітка. Я звик до Lua і можу динамічно створювати 10 + помічників, коли я викликаю одну функцію, і я зробив щось подібне для Python, не використовуючи властивості, і це працює в певній мірі, але, навіть якщо функції створюються раніше що вживаються, часом залишаються проблеми з часом, коли їх називають до створення, що є дивним, оскільки він не закодований таким чином ... Я віддаю перевагу гнучкості мета-таблиць Lua та того факту, я можу використовувати фактичні сетери/геттери замість того, щоб по суті безпосередньо звертатися до змінної ... Мені подобається, як швидко можна побудувати деякі елементи з Python - наприклад, програми gui. хоча той, який я розробляю, може бути недоступним без великої кількості додаткових бібліотек - якщо я кодую його в AutoHotkey, я можу безпосередньо отримати доступ до дзвінків, які мені потрібні, і те ж саме можна зробити в Java, C#, C ++ тощо - можливо, я не знайшли потрібної речі, але для цього проекту я можу перейти з Python ..

Примітка: Вихідний код на цьому форумі не працює - мені довелося додавати пробіли до першої частини коду, щоб вона працювала - при копіюванні/вставці переконайтеся, що ви перетворюєте всі прогалини на вкладки .... Я використовую вкладки для Python, тому що в файл, який складає 10000 рядків, розмір файлу може становити від 512 КБ до 1 Мб з пробілами та від 100 до 200 КБ за допомогою вкладок, що дорівнює масивній різниці для розміру файлу та скорочення часу обробки ...

Вкладки також можуть бути налаштовані на одного користувача - так, якщо ви віддаєте перевагу 2 пробіли шириною 4, 8 або що завгодно, що ви можете зробити це, це означає, що він замислюється для розробників з дефіцитом очей.

Примітка: всі функції, визначені в класі, не відрізняються правильно через помилку в програмному забезпеченні форуму - переконайтеся, що ви вставите його, якщо ви копіюєте/вставляєте

0
додано

Власність може бути оголошена двома способами.

  • Створення методів getter, setter для атрибута, а потім передавати їх як аргумент функції властивість
  • Використовуючи декоратор @property

Ви можете переглянути кілька прикладів, які я написав про властивості в python .

0
додано
ІТ КПІ - Python
ІТ КПІ - Python
625 учасників

Канал обговорень про всякі штуки зі світу пайтону. Прохання: 0. мати повагу одне до одного; 1. не матюкатися в сторону людей; 2. не захламляти тред повідомленнями по одному слову;