Jak działa dekorator @ property w Pythonie?
Chciałbym zrozumieć, jak działa Wbudowana Funkcja property
. Myli mnie to, że property
może być również używany jako dekorator, ale pobiera tylko argumenty, gdy jest używany jako wbudowana funkcja, a nie gdy jest używany jako dekorator.
Ten przykład pochodzi z dokumentacji:
class C:
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
'argumenty s są getx
, setx
, delx
i sznurek doc.
W poniższym kodzie {[2] } jest używany jako dekorator. Jej przedmiotem jest funkcja x
, ale w powyższym kodzie nie ma miejsca na funkcję obiektu w argumentach.
class C:
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
Jak powstają w tym przypadku dekoratory x.setter
i x.deleter
?
14 answers
Funkcja property()
zwraca specjalny obiekt deskryptora :
>>> property()
<property object at 0x10ff07940>
Jest to obiekt, który posiada extra metody:
>>> property().getter
<built-in method getter of property object at 0x10ff07998>
>>> property().setter
<built-in method setter of property object at 0x10ff07940>
>>> property().deleter
<built-in method deleter of property object at 0x10ff07998>
Są one również dekoratorami. Zwracają nowy obiekt Właściwości:
>>> property().getter(None)
<property object at 0x10ff079f0>
Jest to Kopia starego obiektu, ale z wymienioną jedną z funkcji.
Pamiętaj, że składnia @decorator
jest tylko cukrem składniowym; składnia:
@property
def foo(self): return self._foo
Naprawdę oznacza to samo co
def foo(self): return self._foo
foo = property(foo)
Więc foo
funkcja jest zastępowana przez property(foo)
, który widzieliśmy powyżej jest specjalnym obiektem. Następnie, gdy używasz @foo.setter()
, to co robisz, to wywołanie metody property().setter
, którą pokazałem powyżej, która zwraca nową kopię właściwości, ale tym razem z funkcją setter zastąpioną dekorowaną metodą.
Następująca sekwencja również tworzy pełną właściwość, używając tych metod dekoratora.
Najpierw tworzymy kilka funkcji i property
obiekt z 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
Następnie używamy metody .setter()
aby dodać seter:
>>> prop = prop.setter(setter)
>>> prop.fget is getter
True
>>> prop.fset is setter
True
>>> prop.fdel is None
True
Ostatnio dodajemy deleter metodą .deleter()
:
>>> prop = prop.deleter(deleter)
>>> prop.fget is getter
True
>>> prop.fset is setter
True
>>> prop.fdel is deleter
True
Wreszcie, property
obiekt działa jako obiekt deskryptora, więc ma .__get__()
, .__set__()
oraz .__delete__()
metody hakowania do uzyskiwania, ustawiania i usuwania atrybutów instancji:
>>> class Foo: pass
...
>>> prop.__get__(Foo(), Foo)
Get!
>>> prop.__set__(Foo(), 'bar')
Set to 'bar'!
>>> prop.__delete__(Foo())
Delete!
W języku Python jest to implementacja języka Python w Pythonie, a w języku Python jest to implementacja języka Python w Pythonie.]} "type": "content"]}
class Property: "Emulate PyProperty_Type() in Objects/descrobject.c" def __init__(self, fget=None, fset=None, fdel=None, doc=None): self.fget = fget self.fset = fset self.fdel = fdel if doc is None and fget is not None: doc = fget.__doc__ self.__doc__ = doc def __get__(self, obj, objtype=None): if obj is None: return self if self.fget is None: raise AttributeError("unreadable attribute") return self.fget(obj) def __set__(self, obj, value): if self.fset is None: raise AttributeError("can't set attribute") self.fset(obj, value) def __delete__(self, obj): if self.fdel is None: raise AttributeError("can't delete attribute") self.fdel(obj) def getter(self, fget): return type(self)(fget, self.fset, self.fdel, self.__doc__) def setter(self, fset): return type(self)(self.fget, fset, self.fdel, self.__doc__) def deleter(self, fdel): return type(self)(self.fget, self.fset, fdel, self.__doc__)
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-10-20 19:02:14
Dokumentacja mówi, że to tylko skrót do tworzenia właściwości readonly. Więc
@property
def x(self):
return self._x
Jest równoważne
def getx(self):
return self._x
x = property(getx)
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-07-15 20:45:42
Oto minimalny przykład jak @property
może być zaimplementowany:
class Thing:
def __init__(self, my_word):
self._word = my_word
@property
def word(self):
return self._word
>>> print( Thing('ok').word )
'ok'
W przeciwnym razie word
pozostaje metodą zamiast właściwością.
class Thing:
def __init__(self, my_word):
self._word = my_word
def word(self):
return self._word
>>> print( Thing('ok').word() )
'ok'
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-02-15 00:46:29
Pierwsza część jest prosta:
@property
def x(self): ...
Jest tym samym co
def x(self): ...
x = property(x)
- , która z kolei jest uproszczoną składnią do tworzenia {[3] } za pomocą gettera.
Następnym krokiem byłoby rozszerzenie tej właściwości o setter i deleter. I dzieje się tak za pomocą odpowiednich metod:
@x.setter
def x(self, value): ...
Zwraca nową właściwość, która dziedziczy wszystko ze starego x
plus podany setter.
x.deleter
działa tak samo.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-06-26 20:53:15
Poniżej znajduje się kolejny przykład na to, jak @property
może pomóc, gdy trzeba refaktorować kod, który jest pobrany z tutaj (streszczę go tylko poniżej):
Wyobraź sobie, że stworzyłeś klasę Money
w ten sposób:
class Money:
def __init__(self, dollars, cents):
self.dollars = dollars
self.cents = cents
I użytkownik tworzy bibliotekę w zależności od tej klasy, w której używa np.
money = Money(27, 12)
print("I have {} dollar and {} cents.".format(money.dollars, money.cents))
# prints I have 27 dollar and 12 cents.
Teraz Załóżmy, że zdecydujesz się zmienić klasę Money
i pozbyć się atrybutów dollars
i cents
, ale zamiast tego zdecydujesz się śledzić tylko całkowitą ilość
class Money:
def __init__(self, dollars, cents):
self.total_cents = dollars * 100 + cents
Jeśli powyższy użytkownik spróbuje uruchomić swoją bibliotekę tak jak poprzednio
money = Money(27, 12)
print("I have {} dollar and {} cents.".format(money.dollars, money.cents))
Spowoduje to błąd
AttributeError:' Money 'obiekt nie ma atrybutu 'dolary'
Oznacza to, że teraz każdy, kto opiera się na Twojej oryginalnej klasie Money
musiałby zmienić wszystkie linie kodu, w których używane są dollars
i cents
, co może być bardzo bolesne... Jak więc można tego uniknąć? Używając @property
!
To jest jak:
class Money:
def __init__(self, dollars, cents):
self.total_cents = dollars * 100 + cents
# Getter and setter for dollars...
@property
def dollars(self):
return self.total_cents // 100
@dollars.setter
def dollars(self, new_dollars):
self.total_cents = 100 * new_dollars + self.cents
# And the getter and setter for cents.
@property
def cents(self):
return self.total_cents % 100
@cents.setter
def cents(self, new_cents):
self.total_cents = 100 * self.dollars + new_cents
Kiedy teraz dzwonimy z naszej biblioteki
money = Money(27, 12)
print("I have {} dollar and {} cents.".format(money.dollars, money.cents))
# prints I have 27 dollar and 12 cents.
Będzie działać zgodnie z oczekiwaniami i nie musieliśmy zmieniać ani jednej linii kodu w naszej bibliotece! W rzeczywistości nawet nie musielibyśmy wiedzieć, że biblioteka, na której polegamy, zmieniła się.
Również setter
działa dobrze:
money.dollars += 2
print("I have {} dollar and {} cents.".format(money.dollars, money.cents))
# prints I have 29 dollar and 12 cents.
money.cents += 10
print("I have {} dollar and {} cents.".format(money.dollars, money.cents))
# prints I have 29 dollar and 22 cents.
Możesz używać @property
również w klasach abstrakcyjnych; podaję minimalny przykład tutaj .
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-09-16 21:42:39
To:
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
Jest tym samym co:
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.")
Jest tym samym co:
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)
Jest tym samym co:
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)
Czyli to samo co:
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
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-24 18:38:10
Przeczytałem wszystkie posty tutaj i zdałem sobie sprawę, że możemy potrzebować prawdziwego przykładu życia. Dlaczego właściwie mamy @ property?
Rozważ więc aplikację Flask, w której używasz systemu uwierzytelniania.
Użytkownik deklaruje model w 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)
W tym kodzie mamy "Ukryty" atrybut password
za pomocą @property
, który wyzwala AttributeError
assertion, gdy próbujesz uzyskać do niego bezpośredni dostęp, podczas gdy my użyliśmy @property.setter do Ustawienia rzeczywistej zmiennej instancji password_hash
.
Teraz w auth/views.py
możemy utworzyć instancję użytkownika z:
...
@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()
...
Atrybut Notice password
, który pochodzi z formularza rejestracyjnego, gdy użytkownik wypełnia formularz. Potwierdzenie hasła odbywa się na przodzie za pomocą EqualTo('password', message='Passwords must match')
(W przypadku, gdy zastanawiasz się, ale jest to inny temat związany z formami Flask).
Mam nadzieję, że ten przykład będzie przydatny
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-09-10 15:24:43
Zacznijmy od dekoratorów Pythona.
Dekorator Pythona jest funkcją, która pomaga dodać kilka dodatkowych funkcji do już zdefiniowanej funkcji.
W Pythonie wszystko jest obiektem. Funkcje w Pythonie są obiektami pierwszej klasy, co oznacza, że mogą być odwoływane przez zmienną, dodawane do list, przekazywane jako argumenty do innej funkcji itp.
Rozważ następujący fragment kodu.
def decorator_func(fun):
def wrapper_func():
print("Wrapper function started")
fun()
print("Given function decorated")
# Wrapper function add something to the passed function and decorator
# returns the wrapper function
return wrapper_func
def say_bye():
print("bye!!")
say_bye = decorator_func(say_bye)
say_bye()
# Output:
# Wrapper function started
# bye
# Given function decorated
Tutaj możemy powiedzieć, że funkcja dekoratora zmodyfikowaliśmy naszą funkcję say_hello i dodaliśmy do niej kilka dodatkowych linii kodu.
Składnia Pythona dla dekoratora
def decorator_func(fun):
def wrapper_func():
print("Wrapper function started")
fun()
print("Given function decorated")
# Wrapper function add something to the passed function and decorator
# returns the wrapper function
return wrapper_func
@decorator_func
def say_bye():
print("bye!!")
say_bye()
Zakończmy wszystko, niż w przypadku scenariusza, ale wcześniej porozmawiajmy o niektórych UPS priniciples.
Gettery i settery są używane w wielu obiektowych językach programowania, aby zapewnić zasadę enkapsulacji danych (jest postrzegana jako łączenie danych z metodami, które działają na tych danych.)
Te metody są oczywiście getter do pobierania danych i setter do zmiany danych.
Zgodnie z tą zasadą, atrybuty klasy stają się prywatne, aby ukryć je i chronić przed innym kodem.
Yup, @ property jest w zasadzie pythonicznym sposobem użycia getterów i setterów.
Python ma świetną koncepcję o nazwie property, która sprawia, że życie programisty zorientowanego obiektowo jest znacznie prostsze.
Załóżmy, że zdecydujesz się na klasa, która może przechowywać temperaturę w stopniu Celsjusza.
class Celsius:
def __init__(self, temperature = 0):
self.set_temperature(temperature)
def to_fahrenheit(self):
return (self.get_temperature() * 1.8) + 32
def get_temperature(self):
return self._temperature
def set_temperature(self, value):
if value < -273:
raise ValueError("Temperature below -273 is not possible")
self._temperature = value
Refakturowany Kod, oto jak mogliśmy go osiągnąć za pomocą właściwości.
W Pythonie właściwość () jest wbudowaną funkcją, która tworzy i zwraca obiekt Właściwości.
Obiekt właściwości ma trzy metody: getter (), setter () i delete ().
class Celsius:
def __init__(self, temperature = 0):
self.temperature = temperature
def to_fahrenheit(self):
return (self.temperature * 1.8) + 32
def get_temperature(self):
print("Getting value")
return self.temperature
def set_temperature(self, value):
if value < -273:
raise ValueError("Temperature below -273 is not possible")
print("Setting value")
self.temperature = value
temperature = property(get_temperature,set_temperature)
Tutaj,
temperature = property(get_temperature,set_temperature)
Można było podzielić na:
# make empty property
temperature = property()
# assign fget
temperature = temperature.getter(get_temperature)
# assign fset
temperature = temperature.setter(set_temperature)
Uwaga:
- get_temperature remains a właściwość zamiast metody.
Teraz możesz uzyskać dostęp do wartości temperatury przez zapis.
C = Celsius()
C.temperature
# instead of writing C.get_temperature()
Możemy kontynuować i nie definiować nazw get_temperature I set_temperature ponieważ są one niepotrzebne i zanieczyszczają przestrzeń nazw klas.
Sposobem pythonicznym do rozwiązania powyższego problemu jest użycie @ property.
class Celsius:
def __init__(self, temperature = 0):
self.temperature = temperature
def to_fahrenheit(self):
return (self.temperature * 1.8) + 32
@property
def temperature(self):
print("Getting value")
return self.temperature
@temperature.setter
def temperature(self, value):
if value < -273:
raise ValueError("Temperature below -273 is not possible")
print("Setting value")
self.temperature = value
Punkty na uwagę -
- metoda, która jest używana do uzyskania wartości jest ozdobiony napisem "@ property".
- metoda, która ma funkcjonować jako setter, jest dekorowana przez " @ temperature.setter", gdyby funkcja została nazwana "x", musielibyśmy ją ozdobić "@x. setter".
- napisaliśmy" dwie "metody o tej samej nazwie i różnej liczbie parametrów" temperatura def (self) " i " temperatura Def (self, x)".
Jak widać, kod jest zdecydowanie mniej elegancki.
Porozmawiajmy teraz o jednym prawdziwym praktycznym scenerio.
Załóżmy, że zaprojektowałeś klasę w następujący sposób:
class OurClass:
def __init__(self, a):
self.x = a
y = OurClass(10)
print(y.x)
Załóżmy dalej, że nasza klasa stała się popularna wśród klientów i zaczęli używać jej w swoich programach, robili wszelkiego rodzaju przydziały do obiektu.
I pewnego pamiętnego dnia, zaufany klient przyszedł do nas i zasugerował ,że " x " musi być wartością między 0 a 1000, to naprawdę okropny scenariusz!
Ze względu na właściwości jest to proste: tworzymy wersję właściwości "x".
class OurClass:
def __init__(self,x):
self.x = x
@property
def x(self):
return self.__x
@x.setter
def x(self, x):
if x < 0:
self.__x = 0
elif x > 1000:
self.__x = 1000
else:
self.__x = x
To jest świetne, prawda: możesz zacząć od najprostszej implementacji, jaką można sobie wyobrazić, i możesz później migrować do wersji właściwości bez konieczności zmiany interfejsu! Tak więc właściwości nie są tylko zamiennikiem dla getterów i seterów!
Możesz sprawdzić tę implementację tutaj
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-09-16 12:48:14
Ten punkt został wyjaśniony przez wielu ludzi tam, ale tutaj jest bezpośredni punkt, który Szukałem. To jest to, co uważam za ważne, aby zacząć od @ property decorator. eg: -
class UtilityMixin():
@property
def get_config(self):
return "This is property"
Wywołanie funkcji" get_config () " będzie działać w ten sposób.
util = UtilityMixin()
print(util.get_config)
Jeśli zauważysz, że nie użyłem nawiasów "()" do wywołania funkcji. To jest podstawowa rzecz, której szukałem dekoratora @ property. Abyś mógł używać swojej funkcji tak jak zmiennej.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-11-26 06:39:33
property
jest klasą za @property
dekoratorem.
Zawsze możesz to sprawdzić:
print(property) #<class 'property'>
Przepisałem przykład z help(property)
, aby pokazać, że składnia @property
class C:
def __init__(self):
self._x=None
@property
def x(self):
return self._x
@x.setter
def x(self, value):
self._x = value
@x.deleter
def x(self):
del self._x
c = C()
c.x="a"
print(c.x)
Jest funkcjonalnie identyczna z property()
składnia:
class C:
def __init__(self):
self._x=None
def g(self):
return self._x
def s(self, v):
self._x = v
def d(self):
del self._x
prop = property(g,s,d)
c = C()
c.x="a"
print(c.x)
Nie ma różnicy, jak używamy właściwości, jak widać.
Aby odpowiedzieć na pytanie @property
dekorator jest zaimplementowany za pomocą klasy property
.
Więc, pytanie jest, aby wyjaśnić property
Klasa trochę.
To linia:
prop = property(g,s,d)
Była inicjalizacja. Możemy go przepisać tak:
prop = property(fget=g,fset=s,fdel=d)
Znaczenie fget
, fset
i fdel
:
| fget
| function to be used for getting an attribute value
| fset
| function to be used for setting an attribute value
| fdel
| function to be used for del'ing an attribute
| doc
| docstring
Następne zdjęcie pokazuje trojaczki, które mamy, z klasy property
:
__get__
, __set__
, i __delete__
Czy istnieją nadpisane . Jest to implementacja wzorca deskryptora w Pythonie.
Ogólnie rzecz biorąc, deskryptor jest atrybutem obiektu z " zachowaniem wiążącym", takiego, którego dostęp do atrybutów został nadpisany przez metody w protokole deskryptora.
Możemy również użyć właściwości setter
, getter
oraz deleter
metody przypisywania funkcji do właściwości. Sprawdź następny przykład. Metoda s2
klasy C
ustawi właściwość podwojoną .
class C:
def __init__(self):
self._x=None
def g(self):
return self._x
def s(self, x):
self._x = x
def d(self):
del self._x
def s2(self,x):
self._x=x+x
x=property(g)
x=x.setter(s)
x=x.deleter(d)
c = C()
c.x="a"
print(c.x) # outputs "a"
C.x=property(C.g, C.s2)
C.x=C.x.deleter(C.d)
c2 = C()
c2.x="a"
print(c2.x) # outputs "aa"
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-05-26 21:10:22
Najlepsze wyjaśnienie znajdziesz tutaj: Python @ Property Explained-Jak korzystać i kiedy? (Pełne Przykłady) przez Selva Prabhakaran / opublikowano listopad 5, 2018
Pomogło mi zrozumieć, dlaczego nie tylko jak.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-02-25 03:50:04
Właściwość Można zadeklarować na dwa sposoby.
- Tworzenie metod getter, setter dla atrybutu, a następnie przekazywanie ich jako argumentów do właściwości funkcji
- za pomocą dekoratora@property .
Możesz rzucić okiem na kilka przykładów, które napisałem o właściwościach w Pythonie.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-07-13 09:20:51
Oto kolejny przykład:
##
## 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
Zasadniczo tak samo jak w przykładzie C (object), tylko że zamiast tego używam x... Nie inicjalizuję również w _ _ init - ... cóż.. Tak, ale można go usunąć, ponieważ _ _ x jest zdefiniowany jako część klasy....
Wyjście To:
[ Test Class ] Set x = 1234
[ Test Class ] Get x = -1234
[ x ] -1234
I jeśli skomentuję jaźń.x = 1234 in init wtedy wyjście to:
[ Test Class ] Get x = None
[ x ] None
I jeśli ustawiłem _default = None na _default = 0 w funkcji getter (jak wszystkie gettery powinny mieć wartość domyślną, ale nie jest ona przekazywana przez wartości właściwości z tego, co widziałem, więc możesz ją zdefiniować tutaj , i to naprawdę nie jest złe, ponieważ możesz zdefiniować wartość domyślną raz i używać jej wszędzie) ie: def x( self, _default = 0):
[ Test Class ] Get x = 0
[ x ] 0
Uwaga: logika gettera jest po to, aby manipulować wartością, aby upewnić się, że jest manipulowana przez nią - to samo dotyczy instrukcji print...
Uwaga: jestem przyzwyczajony do Lua i jestem w stanie dynamicznie tworzyć pomocników 10+, gdy wywołuję pojedyncza funkcja i zrobiłem coś podobnego dla Pythona bez używania właściwości i działa do pewnego stopnia, ale nawet jeśli funkcje są tworzone przed użyciem, nadal istnieją problemy z ich wywołaniem przed utworzeniem, co jest dziwne, ponieważ nie jest kodowane w ten sposób... Wolę elastyczność Meta-tabel Lua i fakt, że mogę używać rzeczywistych setterów / getterów zamiast zasadniczo bezpośredniego dostępu do zmiennej... Podoba mi się, jak szybko można zbudować pewne rzeczy z Pythonem - na przykład programy gui. chociaż jeden projektuję może nie być możliwy bez wielu dodatkowych bibliotek - jeśli koduję go w AutoHotkey, mogę bezpośrednio uzyskać dostęp do wywołań dll, których potrzebuję, a to samo można zrobić w Javie, C#, C++ i innych - może jeszcze nie znalazłem właściwej rzeczy, ale dla tego projektu mogę przełączyć się z Pythona..
Uwaga: kod wyjściowy na tym forum jest zepsuty - musiałem dodać spacje do pierwszej części kodu, aby działał - podczas kopiowania / wklejania przekonwertuj wszystkie spacje na tabulatory.... Używam tabs dla Pythona, ponieważ w pliku, który jest 10,000 linii Rozmiar pliku może być 512KB do 1MB ze spacjami i 100 do 200KB z tabs, co odpowiada ogromnej różnicy w rozmiarze pliku i skrócenie czasu przetwarzania...
Zakładki można również dostosować dla każdego użytkownika - więc jeśli wolisz szerokość 2 spacji, 4, 8 lub cokolwiek możesz to zrobić, co oznacza, że jest to przemyślane dla programistów z deficytem wzroku.
Uwaga: wszystkie funkcje zdefiniowane w klasy nie są wcięte poprawnie z powodu błędu w oprogramowaniu forum-upewnij się, że wciąłeś je, jeśli skopiujesz / wkleisz
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-08-07 11:08:27
Dekorator jest funkcją, która przyjmuje funkcję jako argument i zwraca zamknięcie. Zamknięcie jest zbiorem funkcji wewnętrznej i zmiennej swobodnej. Funkcja wewnętrzna zamyka się nad zmienną swobodną i dlatego nazywa się ją "zamknięciem". Zmienna swobodna to zmienna, która poza funkcją wewnętrzną i przekazywana jest do wewnętrznej poprzez docorator.
Jak sama nazwa mówi, dekorator dekoruje otrzymaną funkcję.
function decorator(undecorated_func):
print("calling decorator func")
inner():
print("I am inside inner")
return undecorated_func
return inner
Jest to prosta funkcja dekoratora. Otrzymał "undecorated_func" i przeszedł to inner() jako wolna zmienna, inner () wydrukował "I am Inner inner" i zwrócił undecorated_func
. Kiedy wywołujemy decorator(undecorated_func)
, zwracamy inner
. Oto klucz, w dekoratorach nazywamy funkcję wewnętrzną jako nazwę funkcji, którą przekazaliśmy.
undecorated_function= decorator(undecorated_func)
Teraz wewnętrzna funkcja nazywa się "undecorated_func". Ponieważ inner jest teraz nazwany "undecorated_func", przekazaliśmy "undecorated_func" dekoratorowi i zwróciliśmy "undecorated_func" oraz wydrukowaliśmy "I am Inner inner". więc ten wydruk wypowiedź udekorowana naszym "undecorated_func".
Teraz zdefiniujmy klasę z dekoratorem właściwości:
class Person:
def __init__(self,name):
self._name=name
@property
def name(self):
return self._name
@name.setter
def name(self.value):
self._name=value
Kiedy udekorowaliśmy name () znakiem @property (), stało się tak:
name=property(name) # Person.__dict__ you ll see name
Pierwszym argumentem właściwości jest getter. to właśnie stało się w drugiej dekoracji:
name=name.setter(name)
Jak wspomniałem powyżej, dekorator zwraca wewnętrzną funkcję, a funkcję wewnętrzną nazywamy nazwą funkcji, którą przekazaliśmy.
Tutaj jest ważna rzecz, aby być świadomi. "nazwa" jest niezmienna. w pierwszej dekoracji mamy to:
name=property(name)
W drugim mamy to
name=name.setter(name)
Nie modyfikujemy nazwy obj. W drugiej dekoracji python widzi, że jest to obiekt właściwości i już miał getter. Python tworzy więc nowy obiekt" name", dodaje "fget" z pierwszego obj, a następnie ustawia "fset".
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-11-30 21:02:47