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?

Author: Boris, 2013-06-26

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__)
 1079
Author: Martijn Pieters,
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)
 235
Author: J0HN,
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'
 125
Author: AlexG,
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.

 87
Author: glglgl,
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 .

 60
Author: Cleb,
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
 56
Author: Bimo,
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

 22
Author: Leo Skhrnkv,
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ę -

  1. metoda, która jest używana do uzyskania wartości jest ozdobiony napisem "@ property".
  2. metoda, która ma funkcjonować jako setter, jest dekorowana przez " @ temperature.setter", gdyby funkcja została nazwana "x", musielibyśmy ją ozdobić "@x. setter".
  3. 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

 21
Author: Divyanshu Rawat,
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.

 18
Author: Devendra Bhat,
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:

Tutaj wpisz opis obrazka

__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"
 6
Author: prosti,
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.

Https://www.machinelearningplus.com/python/python-property/

 3
Author: Victor Wang,
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.

 1
Author: nvd,
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

 0
Author: Acecool,
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".

 0
Author: Yilmaz,
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