Patrzę na jakiś kod Pythona, który używał tego @
symbolu, ale nie mam pojęcia, co on robi. Nie wiem też, czego szukać, ponieważ wyszukiwanie dokumentów w języku Python lub Google nie zwraca odpowiednich wyników, gdy ten @
symbol jest dołączony.
python
syntax
python-decorators
AJ00200
źródło
źródło
Przykład
To pokazuje, że
function
/method
/,class
które definiujesz po dekoratorze, jest po prostu przekazywaneargument
dofunction
/method
bezpośrednio po@
znaku.Pierwsze spojrzenie
Mikroframa Flask wprowadza dekoratorów od samego początku w następującym formacie:
To z kolei przekłada się na:
Uświadomienie sobie tego wreszcie pozwoliło mi poczuć się spokojnie z Flask.
źródło
app.route("/")
: ta funkcja zwraca funkcję, którą wywołujeszhello()
jako argumentapp.route("/", hello)
natychmiast po zdefiniowaniuhello
, a nawet zdefiniowaniahello
jako lambda w argumentachapp.route
? (Drugi przykład jest wspólny dlahttp.Server
tras Node.js i Express).Ten fragment kodu:
Jest równoważny z tym kodem:
W definicji dekoratora możesz dodać zmodyfikowane rzeczy, które normalnie nie byłyby zwracane przez funkcję.
źródło
W Pythonie 3.5 można przeciążać
@
jako operator. Nazywa się tak__matmul__
, ponieważ jest przeznaczony do mnożenia macierzy, ale może być czymkolwiek chcesz. Szczegóły znajdują się w PEP465 .Jest to prosta implementacja mnożenia macierzy.
Ten kod daje:
źródło
@=
operator (lokalny), czyli__imatmul__
.__add__
i jestem__sub__
powiązany odpowiednio z + i -, ale nigdy wcześniej nie słyszałem o@
znaku. Czy są tam jeszcze inni?Co robi symbol „at” (@) w Pythonie?
W skrócie, jest on używany w składni dekoratora i do mnożenia macierzy.
W kontekście dekoratorów ta składnia:
jest równoważne z tym:
W kontekście mnożenia macierzy
a @ b
wywołujea.__matmul__(b)
- czyniąc tę składnię:równoważny
i
równoważny
gdzie
dot
jest, na przykład, funkcja mnożenia macierzy numpya
ib
są macierzami.Jak mogłeś to odkryć na własną rękę?
Jeśli chcesz mieć dość pełny obraz tego, co robi konkretna część składni Pythona, spójrz bezpośrednio na plik gramatyki. W przypadku gałęzi Python 3:
Widzimy tutaj, który
@
jest używany w trzech kontekstach:Składnia dekoratora:
Wyszukiwarka google „dekorator python docs” podaje jako jeden z najlepszych wyników sekcję „Instrukcje złożone” w „Python Language Reference”. Przewijając w dół do sekcji definicji funkcji , którą możemy znaleźć, szukając słowa „dekorator”, widzimy, że… jest wiele do przeczytania. Ale słowo „dekorator” to link do glosariusza , który mówi nam:
Widzimy to
jest semantycznie taki sam jak:
Nie są one dokładnie takie same, ponieważ Python ocenia wyrażenie foo (które może być wyszukiwaniem kropkowym i wywołaniem funkcji) przed słupkiem za pomocą
@
składni decorator ( ), ale w innym przypadku ocenia wyrażenie foo po słupku.(Jeśli ta różnica ma znaczenie w znaczeniu twojego kodu, powinieneś ponownie rozważyć to, co robisz ze swoim życiem, ponieważ byłoby to patologiczne).
Ułożone dekoratorów
Jeśli wrócimy do dokumentacji składni definicji funkcji, zobaczymy:
Jest to demonstracja, że możemy wywołać funkcję, która najpierw jest dekoratorem, a także dekoratorami stosu. Funkcje w Pythonie są obiektami pierwszej klasy - co oznacza, że możesz przekazać funkcję jako argument do innej funkcji i zwrócić funkcje. Dekoratorzy robią obie te rzeczy.
Jeśli ułożymy dekoratory w stos, funkcja, zgodnie z definicją, zostanie najpierw przekazana dekoratorowi bezpośrednio nad nią, a następnie następna i tak dalej.
To wszystko podsumowuje użycie
@
w kontekście dekoratorów.Operator
@
W sekcji analizy leksykalnej odwołania do języka mamy sekcję dotyczącą operatorów , która zawiera
@
, co czyni ją również operatorem:a na następnej stronie Model danych mamy sekcję Emulowanie typów numerycznych ,
I widzimy, że to
__matmul__
odpowiada@
. Jeśli przeszukamy dokumentację pod kątem „matmul”, otrzymujemy link do Co nowego w Pythonie 3.5 z „matmul” pod nagłówkiem „PEP 465 - Dedykowany operator infix do mnożenia macierzy”.(Więc teraz dowiadujemy się, że
@=
jest to wersja na miejscu). Wyjaśnia ponadto:Podczas gdy ten operator może być przeciążony, aby zrobić prawie wszystko,
numpy
na przykład użylibyśmy tej składni do obliczenia wewnętrznego i zewnętrznego produktu tablic i macierzy:Mnożenie macierzy w miejscu:
@=
Badając wcześniejsze użycie, dowiadujemy się, że istnieje również wewnętrzne mnożenie macierzy. Jeśli spróbujemy go użyć, może się okazać, że nie jest jeszcze zaimplementowany dla numpy:
Po wdrożeniu oczekiwałbym, że wynik będzie wyglądał następująco:
źródło
Symbol @ to syntaktyczny python z cukrem, który można wykorzystać
decorator
,aby sparafrazować pytanie: To dokładnie o tym, co robi dekorator w Pythonie?
Upraszczając,
decorator
możesz zmodyfikować definicję danej funkcji bez dotykania jej od środka (jej zamknięcia).Jest to najbardziej przypadek, gdy importujesz wspaniały pakiet od strony trzeciej. Możesz to sobie wyobrazić, możesz z niego korzystać, ale nie możesz dotknąć jego wnętrza i serca.
Oto szybki przykład,
załóżmy , że zdefiniowałem
read_a_book
funkcję na IpythonWidzisz, zapomniałem dodać do niego nazwę.
Jak rozwiązać taki problem? Oczywiście mógłbym ponownie zdefiniować funkcję jako:
Niemniej jednak, jeśli nie wolno mi manipulować oryginalną funkcją lub jeśli istnieją tysiące takich funkcji do obsłużenia.
Rozwiąż problem, myśląc inaczej i zdefiniuj nową funkcję
Więc zastosuj to.
Tada, widzicie, poprawiłem
read_a_book
bez dotykania jej wewnętrznego zamknięcia. Nic mnie nie powstrzymadecorator
.O co chodzi
@
@add_a_book
to fantazyjny i wygodny sposób na stwierdzenieread_a_book = add_a_book(read_a_book)
, że to cukier składniowy, nie ma w tym nic bardziej wyszukanego.źródło
Jeśli odwołujesz się do jakiegoś kodu w notatniku Pythona, który korzysta z biblioteki Numpy ,
@ operator
oznacza to mnożenie macierzy . Na przykład:źródło
Począwszy od Python 3.5, „@” jest używany jako dedykowany symbol poprawki dla MATRIX MULTIPLICATION (PEP 0465 - patrz https://www.python.org/dev/peps/pep-0465/ )
źródło
W Pythonie dodano dekoratory, aby łatwiej było czytać i rozumieć zawijanie funkcji i metod (funkcja, która odbiera funkcję i zwraca ulepszoną). Pierwotny przypadek użycia miał być w stanie zdefiniować metody jako metody klasowe lub metody statyczne na początku ich definicji. Bez składni dekoratora wymagałoby to raczej rzadkiej i powtarzalnej definicji:
Jeśli składnia dekoratora jest używana w tym samym celu, kod jest krótszy i łatwiejszy do zrozumienia:
Ogólna składnia i możliwe implementacje
Dekorator jest generalnie nazwanym obiektem ( wyrażenia lambda nie są dozwolone ), który akceptuje pojedynczy argument po wywołaniu (będzie to funkcja dekorowana) i zwraca inny obiekt możliwy do wywołania. Używa się tutaj „wywoływalnego” zamiast „funkcji” z premedytacją. Podczas gdy dekoratorzy są często dyskutowani w zakresie metod i funkcji, nie są do nich ograniczeni. W rzeczywistości wszystko, co można wywoływać (każdy obiekt, który implementuje metodę _call__ jest uważany za wywoływalny), może być używane jako dekorator, a często zwracane przez nie obiekty nie są prostymi funkcjami, ale bardziej instancjami bardziej złożonych klas implementujących własną metodę __call_.
Składnia dekoratora to po prostu tylko cukier składniowy . Rozważ następujące użycie dekoratora:
Zawsze można to zastąpić jawnym wywołaniem dekoratora i ponownym przypisaniem funkcji:
Jednak ta ostatnia jest mniej czytelna, a także bardzo trudna do zrozumienia, jeśli na jednej funkcji użyto wielu dekoratorów. Dekoratorów można używać na wiele różnych sposobów, jak pokazano poniżej:
Jako funkcja
Istnieje wiele sposobów pisania niestandardowych dekoratorów, ale najprostszym sposobem jest napisanie funkcji, która zwraca podfunkcję, która otacza oryginalne wywołanie funkcji.
Ogólne wzorce są następujące:
Jako klasa
Chociaż dekoratory prawie zawsze można zaimplementować za pomocą funkcji, w niektórych sytuacjach lepszym rozwiązaniem jest użycie klas zdefiniowanych przez użytkownika. Jest to często prawdziwe, gdy dekorator wymaga złożonej parametryzacji lub zależy to od określonego stanu.
Ogólny wzór dla niesparametryzowanego dekoratora jako klasy jest następujący:
Parametryzacja dekoratorów
W prawdziwym kodzie często zachodzi potrzeba użycia dekoratorów, które można sparametryzować. Gdy funkcja jest używana jako dekorator, wówczas rozwiązanie jest proste - należy zastosować drugi poziom owijania. Oto prosty przykład dekoratora, który powtarza wykonanie dekorowanej funkcji określoną liczbę razy za każdym razem, gdy jest wywoływana:
Dekorator zdefiniowany w ten sposób może akceptować parametry:
Zauważ, że nawet jeśli sparametryzowany dekorator ma domyślne wartości dla swoich argumentów, wymagane są nawiasy po nazwie. Prawidłowy sposób użycia poprzedniego dekoratora z domyślnymi argumentami jest następujący:
Wreszcie pozwala zobaczyć dekoratorów z właściwościami.
Nieruchomości
Właściwości zapewniają wbudowany typ deskryptora, który wie, jak połączyć atrybut z zestawem metod. Właściwość przyjmuje cztery opcjonalne argumenty: fget, fset, fdel i doc. Ostatni można podać w celu zdefiniowania ciągu dokumentów, który jest powiązany z atrybutem tak, jakby to była metoda. Oto przykład klasy Rectangle, którą można kontrolować poprzez bezpośredni dostęp do atrybutów przechowujących dwa punkty narożne lub za pomocą właściwości width i height:
Najlepszą składnią do tworzenia właściwości jest użycie właściwości jako dekoratora. Spowoduje to zmniejszenie liczby podpisów metod wewnątrz klasy i sprawi, że kod będzie bardziej czytelny i łatwy w utrzymaniu . Dzięki dekoratorom powyższa klasa staje się:
źródło
Powiedzieć, co mają inni w inny sposób: tak, to dekorator.
W Pythonie wygląda to tak:
Można to wykorzystać do wszelkiego rodzaju przydatnych rzeczy, co jest możliwe, ponieważ funkcje są obiektami i tylko niezbędnymi instrukcjami.
źródło
@ Symbol jest również stosowany do zmiennych dostępu w plydata / pandy dataframe kwerendy
pandas.DataFrame.query
. Przykład:źródło
Wskazuje, że używasz dekoratora. Oto przykład Bruce'a Eckela z 2008 roku.
źródło