Chciałbym zrozumieć, jak property
działa funkcja wbudowana . To, co mnie dezorientuje, to fakt, że property
można go również używać jako dekoratora, ale wymaga tylko argumentów, gdy jest używany jako funkcja wbudowana, a nie jako dekorator.
Ten przykład pochodzi z dokumentacji :
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 argumenty są getx
, setx
, delx
a ciąg doc.
W poniższym kodzie property
zastosowano jako dekorator. Jego przedmiotem jest x
funkcja, ale w powyższym kodzie nie ma miejsca na funkcję obiektu w argumentach.
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
Jak powstają dekoratorzy x.setter
i x.deleter
dekoratorzy? Jestem zdezorientowany.
property
jest w rzeczywistości klasą (a nie funkcją), chociaż prawdopodobnie wywołuje__init__()
metodę podczas tworzenia obiektu, oczywiście. Korzystaniehelp(property)
z terminala jest wnikliwe.help
jest także klasą z jakiegoś powodu.Odpowiedzi:
property()
Zwraca szczególną obiekt deskryptora :Ten obiekt ma dodatkowe metody:
Działają one jak dekoratorów zbyt . Zwracają nowy obiekt właściwości:
jest to kopia starego obiektu, ale z zastąpioną jedną z funkcji.
Pamiętaj, że
@decorator
składnia to tylko cukier składniowy; składnia:naprawdę oznacza to samo co
więc
foo
funkcja jest zastąpiona przezproperty(foo)
, co widzieliśmy powyżej, jest obiektem specjalnym. Następnie, gdy używasz@foo.setter()
, wywołujeszproperty().setter
metodę, którą pokazałem powyżej, która zwraca nową kopię właściwości, ale tym razem z funkcją ustawiającą zastąpioną metodą dekorowaną.Poniższa sekwencja tworzy również właściwość full-on przy użyciu tych metod dekoratora.
Najpierw tworzymy niektóre funkcje i
property
obiekt za pomocą gettera:Następnie używamy
.setter()
metody, aby dodać seter:Na koniec dodajemy deleter za pomocą
.deleter()
metody:Last but not least,
property
obiekt działa jako obiektu deskryptora , a więc ma.__get__()
,.__set__()
i.__delete__()
sposoby, aby podłączyć się do atrybutu instancji uzyskanie, ustawiania i usuwania:Deskryptorze Howto zawiera czystą przykładową realizację Pythona w
property()
rodzaju:źródło
Foo.prop = prop
można zrobićFoo().prop = 5; pront Foo().prop; del Foo().prop
z pożądanego rezultatu.type()
jako dostępu do atrybutów dundera, a metody mają służyć jako punkty rozszerzenia przez standardowe funkcje i operatory.@human.name.getter
zmienionoproperty
obiekt w miejscu zamiast zwrócić nowy,human.name
atrybut zostałby zmieniony, zmieniając zachowanie tej nadklasy.Dokumentacja mówi, że to tylko skrót do tworzenia właściwości tylko do odczytu. Więc
jest równa
źródło
@property
dekoratorem w swojej klasie.Oto minimalny przykład tego, jak
@property
można go wdrożyć:W przeciwnym razie
word
pozostaje metoda zamiast właściwości.źródło
self.word = my_word
print( Thing('ok').word ) = 'ok'
Thing('ok').word
wywołuje tę funkcję wewnętrznie w czasie wykonywania?Pierwsza część jest prosta:
jest taki sam jak
property
z tylko geterem.Następnym krokiem byłoby rozszerzenie tej właściwości o seter i deleter. A dzieje się to za pomocą odpowiednich metod:
zwraca nową właściwość, która dziedziczy wszystko po starym
x
plus podany setter.x.deleter
działa w ten sam sposób.źródło
To następujące:
Jest taki sam jak:
Jest taki sam jak:
Jest taki sam jak:
Który jest taki sam jak:
źródło
Poniżej znajduje się kolejny przykład, w jaki sposób
@property
można pomóc, gdy trzeba ponownie kodować kod pobrany z tego miejsca (podsumowuję go tylko poniżej):Wyobraź sobie, że stworzyłeś taką klasę
Money
:a użytkownik tworzy bibliotekę w zależności od tej klasy, z której korzysta np
Załóżmy teraz, że zdecydujesz się zmienić
Money
klasę i pozbyć się atrybutówdollars
i,cents
ale zamiast tego zdecydujesz się śledzić tylko całkowitą liczbę centów:Jeśli wyżej wspomniany użytkownik próbuje teraz uruchomić swoją bibliotekę jak poprzednio
spowoduje błąd
Oznacza to, że teraz każdy, kto opiera się na oryginalnej
Money
klasie, musiałby zmienić wszystkie wiersze kodu gdziedollars
icents
są używane, co może być bardzo bolesne ... Jak więc można tego uniknąć? Za pomocą@property
!To w jaki sposób:
kiedy teraz dzwonimy z naszej biblioteki
będzie działać zgodnie z oczekiwaniami i nie musieliśmy zmieniać ani jednego wiersza kodu w naszej bibliotece! W rzeczywistości nie musielibyśmy nawet wiedzieć, że biblioteka, na której polegamy, uległa zmianie.
Również
setter
działa dobrze:Możesz używać
@property
również w klasach abstrakcyjnych; Daję minimalny przykład tutaj .źródło
self.dollar = dollars
? tyle zrobiliśmy z @property, ale wygląda na to, że nie dodano żadnej funkcji wyodrębniania.Przeczytałem wszystkie posty tutaj i zdałem sobie sprawę, że możemy potrzebować prawdziwego przykładu. Dlaczego właściwie mamy @ właściwość? Rozważ więc aplikację Flask, w której korzystasz z systemu uwierzytelniania. Użytkownik deklaruje model użytkownika w
models.py
:W tym kodzie mamy „ukryty” atrybut,
password
za pomocą@property
którego wyzwala sięAttributeError
potwierdzenie, gdy próbujesz uzyskać do niego bezpośredni dostęp, podczas gdy użyliśmy @ property.setter, aby ustawić rzeczywistą zmienną instancjipassword_hash
.Teraz
auth/views.py
możemy utworzyć użytkownika za pomocą:Zauważ atrybut,
password
który pochodzi z formularza rejestracyjnego, gdy użytkownik wypełnia formularz. Potwierdzenie hasła odbywa się na interfejsie użytkownikaEqualTo('password', message='Passwords must match')
(na wypadek, gdybyś się zastanawiał, ale jest to inny temat związany z formularzami Flask).Mam nadzieję, że ten przykład się przyda
źródło
Ten punkt został wyjaśniony przez wielu ludzi tam, ale tutaj jest punkt bezpośredni, którego szukałem. Uważam, że to ważne, aby zacząć od dekoratora @property. na przykład:-
Wywołanie funkcji „get_config ()” będzie działać w ten sposób.
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 jak zmiennej.
źródło
Zacznijmy od dekoratorów Python.
Dekorator Python to funkcja, która pomaga dodać dodatkowe funkcje do już zdefiniowanej funkcji.
W Pythonie wszystko jest przedmiotem. Funkcje w Pythonie są pierwszorzędnymi obiektami, co oznacza, że można do nich odwoływać się zmienną, dodawać do list, przekazywać jako argumenty do innej funkcji itp.
Rozważ następujący fragment kodu.
Tutaj możemy powiedzieć, że funkcja dekoratora zmodyfikowała naszą funkcję say_hello i dodała w niej kilka dodatkowych wierszy kodu.
Składnia Pythona dla dekoratora
Podsumujmy wszystko niż scenariusz przypadku, ale wcześniej porozmawiajmy o niektórych głównych zasadach.
Gettery i settery są używane w wielu obiektowych językach programowania, aby zapewnić zasadę enkapsulacji danych (jest to postrzegane jako wiązanie danych z metodami operującymi na tych danych).
Te metody są oczywiście narzędziem pobierającym dane i ustawiającym dane.
Zgodnie z tą zasadą atrybuty klasy są prywatne, aby je ukryć i chronić przed innym kodem.
Tak, @property jest w zasadzie pytonicznym sposobem używania programów pobierających i ustawiających.
Python ma świetną koncepcję zwaną właściwością, która znacznie upraszcza życie programisty obiektowego.
Załóżmy, że zdecydujesz się stworzyć klasę, która może przechowywać temperaturę w stopniach Celsjusza.
Refactored Code, oto jak moglibyśmy to osiągnąć za pomocą nieruchomości.
W Pythonie property () 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 ().
Tutaj,
mógł zostać rozbity, ponieważ
Uwaga:
Teraz możesz uzyskać dostęp do wartości temperatury pisząc.
Możemy dalej iść i nie definiować nazw get_temperature i set_temperature, ponieważ są one niepotrzebne i zanieczyszczają przestrzeń nazw klas.
Pythonic sposób radzić sobie z powyższego problemu jest użycie @property .
Punkty do odnotowania -
Jak widać, kod jest zdecydowanie mniej elegancki.
Porozmawiajmy teraz o jednym praktycznym scenariuszu z życia.
Powiedzmy, że zaprojektowałeś klasę w następujący sposób:
Teraz załóżmy dalej, że nasza klasa stała się popularna wśród klientów i zaczęli używać jej w swoich programach, wykonywali wszelkiego rodzaju przypisania do obiektu.
Pewnego pamiętnego dnia przyszedł do nas zaufany klient i zasugerował, że „x” musi być wartością od 0 do 1000, to naprawdę okropny scenariusz!
Ze względu na właściwości jest to łatwe: tworzymy wersję właściwości „x”.
To wspaniale, prawda? Możesz zacząć od najprostszej możliwej implementacji i możesz później migrować do wersji właściwości bez konieczności zmiany interfejsu! Więc właściwości nie są tylko zamiennikiem dla pobierających i ustawiających!
Możesz sprawdzić tę implementację tutaj
źródło
property
jest klasą stojącą za@property
dekoratorem.Zawsze możesz to sprawdzić:
Przepisałem przykład z,
help(property)
aby pokazać, że@property
składniajest funkcjonalnie identyczny ze
property()
składnią:Jak widać, nie ma różnicy, w jaki sposób korzystamy z nieruchomości.
Aby odpowiedzieć na pytanie,
@property
dekorator jest wdrażany za pośrednictwemproperty
klasy.Zatem pytanie polega na tym,
property
aby trochę wyjaśnić klasę. Ta linia:Była inicjalizacja. Możemy przepisać to w następujący sposób:
Rozumieniu
fget
,fset
ifdel
:Następny obraz pokazuje trojaczki, które mamy, z klasy
property
:__get__
,__set__
i czy__delete__
są tam do zastąpienia . Jest to implementacja wzorca deskryptora w Pythonie.Możemy również korzystać z własności
setter
,getter
adeleter
metody wiążą funkcję mienia. Sprawdź następny przykład. Metodas2
klasyC
spowoduje podwojenie właściwości .źródło
Właściwość można zadeklarować na dwa sposoby.
Możesz rzucić okiem na kilka przykładów, które napisałem o właściwościach w pythonie .
źródło
Najlepsze wyjaśnienie można znaleźć tutaj: Wyjaśnienie Python @ Właściwość - jak używać i kiedy? (Pełne przykłady) Selva Prabhakaran | Wysłany 5 listopada 2018 r
Pomogło mi zrozumieć DLACZEGO nie tylko JAK.
https://www.machinelearningplus.com/python/python-property/
źródło
Oto inny przykład:
Zasadniczo to samo co w przykładzie C (obiekt), z tym że zamiast tego używam x ... Nie inicjuję też w __init - ... cóż .. Robię, ale można go usunąć, ponieważ __x jest zdefiniowany jako część z klasy ....
Dane wyjściowe to:
a jeśli skomentuję self.x = 1234 w init, to wynik będzie:
i jeśli ustawię _default = None na _default = 0 w funkcji gettera (ponieważ wszystkie gettery powinny mieć wartość domyślną, ale nie są przekazywane przez wartości właściwości z tego, co widziałem, aby można było ją tutaj zdefiniować, i tak naprawdę nie jest źle, ponieważ możesz zdefiniować wartość domyślną raz i używać jej wszędzie) tj .: def x (self, _default = 0):
Uwaga: Logika pobierająca jest po to, aby manipulować wartością, aby upewnić się, że jest nią manipulowana - to samo dla instrukcji print ...
Uwaga: Jestem przyzwyczajony do Lua i jestem w stanie dynamicznie tworzyć ponad 10 pomocników, gdy wywołuję pojedynczą funkcję, i stworzyłem coś podobnego do Pythona bez użycia właściwości i działa do pewnego stopnia, ale mimo że funkcje są tworzone wcześniej gdy są używane, czasami pojawiają się problemy z ich wywoływaniem przed utworzeniem, co jest dziwne, ponieważ nie jest tak kodowane ... 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 za pomocą Pythona - na przykład programy GUI. chociaż jedna, którą projektuję, może nie być możliwa bez wielu dodatkowych bibliotek - jeśli koduję to w AutoHotkey, mogę bezpośrednio uzyskać dostęp do wywołań dll, których potrzebuję, i to samo można zrobić w Javie, C #, C ++,
Uwaga: Kod wyjściowy na tym forum jest zepsuty - musiałem dodać spacje do pierwszej części kodu, aby działał - podczas kopiowania / wklejania upewnij się, że przekonwertowałeś wszystkie spacje na tabulatory .... Używam tabulatorów w Pythonie, ponieważ w plik, który ma 10 000 wierszy, rozmiar pliku może wynosić od 512 KB do 1 MB ze spacjami i od 100 do 200 KB z tabulatorami, co odpowiada ogromnej różnicy rozmiaru pliku i skróceniu czasu przetwarzania ...
Tabulatory można również regulować dla każdego użytkownika - więc jeśli wolisz szerokość 2 spacji, 4, 8 lub cokolwiek innego, co możesz zrobić, oznacza to, że jest to rozważne dla programistów z deficytem wzroku.
Uwaga: Wszystkie funkcje zdefiniowane w klasie nie są prawidłowo wcięte z powodu błędu w oprogramowaniu forum - upewnij się, że wcinasz je, jeśli kopiujesz / wklejasz
źródło
Jedna uwaga: dla mnie, dla Python 2.x,
@property
nie działał tak jak reklamowano, gdy nie dziedziczyłem poobject
:ale działało, gdy:
dla Pythona 3 działało zawsze.
źródło
object
jest klasą w starym stylu, a klasy w starym stylu nie obsługują protokołu deskryptora (któryproperty
implementuje się tak, jak działa). W Pythonie 3 klasy w starym stylu już nie istnieją; wszystkie klasy nazywamy klasami nowego stylu w Pythonie 2.