Wiem, że __call__
metoda w klasie jest wyzwalana, gdy wywoływana jest instancja klasy. Nie mam jednak pojęcia, kiedy mogę użyć tej specjalnej metody, ponieważ można po prostu utworzyć nową metodę i wykonać tę samą operację, co w __call__
metodzie i zamiast wywoływać instancję, można wywołać metodę.
Byłbym bardzo wdzięczny, gdyby ktoś dał mi praktyczne zastosowanie tej specjalnej metody.
python
methods
call
magic-methods
mohi666
źródło
źródło
__call__
jest ukryte na widoku; tak tworzysz instancję klasy:x = Foo()
jest naprawdęx = type(Foo).__call__(Foo)
, gdzie__call__
jest zdefiniowana przez metaklasęFoo
.Odpowiedzi:
Moduł formularzy Django
__call__
ładnie wykorzystuje metodę do implementacji spójnego API do walidacji formularzy. Możesz napisać swój własny walidator dla formularza w Django jako funkcję.Django ma kilka domyślnych wbudowanych walidatorów, takich jak walidatory poczty e-mail, walidatory adresów URL itp., Które zasadniczo należą do walidatorów RegEx. Aby zaimplementować je w czysty sposób, Django ucieka się do wywoływanych klas (zamiast funkcji). Implementuje domyślną logikę walidacji Regex w RegexValidator, a następnie rozszerza te klasy o inne walidacje.
Teraz zarówno twoja funkcja niestandardowa, jak i wbudowany EmailValidator mogą być wywoływane z tą samą składnią.
Jak widać, ta implementacja w Django jest podobna do tego, co inni wyjaśnili w swoich odpowiedziach poniżej. Czy można to zaimplementować w inny sposób? Mógłbyś, ale IMHO nie będzie tak czytelny ani tak łatwo rozszerzalny dla dużego frameworka, takiego jak Django.
źródło
W tym przykładzie użyto zapamiętywania , zasadniczo przechowując wartości w tabeli (w tym przypadku w słowniku), dzięki czemu można je później wyszukać, zamiast ponownie je obliczać.
Tutaj używamy prostej klasy z
__call__
metodą do obliczania silni (za pomocą wywoływalnego obiektu ) zamiast funkcji silni, która zawiera zmienną statyczną (ponieważ nie jest to możliwe w Pythonie).Teraz masz
fact
obiekt, który jest wywoływalny, tak jak każda inna funkcja. Na przykładI jest również stanowy.
źródło
fact
obiekt, który można indeksować, ponieważ twoja__call__
funkcja jest zasadniczo indeksem. Użyłby też listy zamiast dyktowania, ale to tylko ja.__call__
, być prostym i niczym więcej.Uważam to za przydatne, ponieważ pozwala mi tworzyć interfejsy API, które są łatwe w użyciu (masz obiekt wywoływalny, który wymaga określonych argumentów) i są łatwe do wdrożenia, ponieważ możesz używać praktyk zorientowanych obiektowo.
Poniżej znajduje się kod, który napisałem wczoraj, który tworzy wersję
hashlib.foo
metod, która haszuje całe pliki zamiast ciągów:Ta implementacja pozwala mi korzystać z funkcji w podobny sposób do
hashlib.foo
funkcji:Oczywiście mogłem to zaimplementować w inny sposób, ale w tym przypadku wydawało się to prostym podejściem.
źródło
__call__
dostaniesz narzędzie, które pozwoli ci używać technik OO do rozwiązywania problemów.isinstance
lub coś podobnego.__call__
metody zamiast zamknięcia, jest sytuacja, w której masz do czynienia z modułem wieloprocesowym, który wykorzystuje wytrawianie do przekazywania informacji między procesami. Nie możesz wytrawić zamknięcia, ale możesz wytrawić wystąpienie klasy.__call__
jest również używany do implementowania klas dekoratorów w Pythonie. W tym przypadku instancja klasy jest wywoływana, gdy wywoływana jest metoda z dekoratorem.źródło
Tak, kiedy wiesz, że masz do czynienia z obiektami, jest całkowicie możliwe (aw wielu przypadkach zalecane) użycie jawnego wywołania metody. Czasami jednak masz do czynienia z kodem, który oczekuje wywoływalnych obiektów - zwykle funkcji, ale dzięki temu
__call__
możesz budować bardziej złożone obiekty, z danymi instancji i większą liczbą metod do delegowania powtarzalnych zadań itp., Które są nadal wywoływalne.Ponadto czasami używasz zarówno obiektów do złożonych zadań (gdzie sensowne jest napisanie dedykowanej klasy), jak i obiektów do prostych zadań (które już istnieją w funkcjach lub są łatwiejsze do zapisania jako funkcje). Aby mieć wspólny interfejs, musisz albo napisać małe klasy opakowujące te funkcje w oczekiwany interfejs, albo zachować funkcje funkcji i sprawić, by bardziej złożone obiekty były wywoływalne. Weźmy jako przykład wątki. Te
Thread
obiekty ze standardowego modułu libarythreading
chcą wywoływalnym jakotarget
argumentu (czyli jako działanie do wykonania w nowym wątku). W przypadku wywoływalnego obiektu nie jesteś ograniczony do funkcji, możesz również przekazywać inne obiekty, takie jak stosunkowo złożony proces roboczy, który pobiera zadania z innych wątków i wykonuje je sekwencyjnie:To tylko przykład z góry mojej głowy, ale myślę, że jest już wystarczająco złożony, aby uzasadnić klasę. Robienie tego tylko z funkcjami jest trudne, przynajmniej wymaga zwrócenia dwóch funkcji, a to powoli się komplikuje. Jeden mógł zmienić nazwę
__call__
na coś innego i przekazać metodę związaną, ale sprawia, że kod tworząc nieco mniej oczywisty wątek, a nie dodaje żadnej wartości.źródło
__call__
że używam instancji klas (zamiast funkcji) jako aplikacji WSGI. Oto przykład z „The Definitive Guide to Pylons”: Using Instances of ClassesDekoratory oparte na klasach używają
__call__
do odwoływania się do opakowanej funkcji. Na przykład:W witrynie Artima.com znajduje się dobry opis różnych opcji
źródło
__call__
Metoda IMHO i domknięcia dają nam naturalny sposób tworzenia wzorca projektowego STRATEGY w Pythonie. Definiujemy rodzinę algorytmów, hermetyzujemy każdy z nich, sprawiamy, że są wymienne i na koniec możemy wykonać wspólny zestaw kroków i na przykład obliczyć hash dla pliku.źródło
Właśnie natknąłem się na użycie
__call__()
na koncercie, z__getattr__()
którym uważam, że jest piękny. Pozwala na ukrycie wielu poziomów API JSON / HTTP / (jednak_serializowanego) wewnątrz obiektu.__getattr__()
Część zajmuje iteracyjnie powrocie zmodyfikowanej wystąpienie tej samej klasy, wypełniając w jednym więcej atrybutów naraz. Następnie, po wyczerpaniu wszystkich informacji,__call__()
przejmuje wszystkie podane przez Ciebie argumenty.Korzystając z tego modelu, możesz na przykład wykonać połączenie typu
api.v2.volumes.ssd.update(size=20)
, które kończy się żądaniem PUT dohttps://some.tld/api/v2/volumes/ssd/update
.Konkretny kod jest sterownikiem pamięci blokowej dla określonego zaplecza woluminu w OpenStack, możesz to sprawdzić tutaj: https://github.com/openstack/cinder/blob/master/cinder/volume/drivers/nexenta/jsonrpc.py
EDYCJA: Zaktualizowano łącze, aby wskazywało wersję główną.
źródło
Określ a
__metaclass__
i przesłoń__call__
metodę, a metoda określonych meta-klas__new__
zwróci instancję klasy, albowiem masz „funkcję” z metodami.źródło
Możemy użyć
__call__
metody, aby użyć innych metod klas jako metod statycznych.źródło
Jednym z typowych przykładów jest
__call__
infunctools.partial
, tutaj jest uproszczona wersja (z Pythonem> = 3.5):Stosowanie:
źródło
Operator wywołania funkcji.
Metoda __call__ może zostać użyta do przedefiniowania / ponownej inicjalizacji tego samego obiektu. Ułatwia również używanie instancji / obiektów klasy jako funkcji poprzez przekazywanie argumentów do obiektów.
źródło
I znaleźć miejsce dobre do wykorzystania wywołalnych przedmioty, takie, które określają
__call__()
, czy podczas korzystania z możliwości funkcjonalnych programowania w Pythonie, takie jakmap()
,filter()
,reduce()
.Najlepszym momentem na użycie wywoływalnego obiektu zamiast zwykłej funkcji lub funkcji lambda jest sytuacja, gdy logika jest złożona i musi zachować pewien stan lub używa innych informacji, które nie są przekazywane do
__call__()
funkcji.Oto kod, który filtruje nazwy plików na podstawie ich rozszerzenia przy użyciu wywoływalnego obiektu i
filter()
.Możliwość wywołania:
Stosowanie:
Wynik:
źródło
Jest już za późno, ale podaję przykład. Wyobraź sobie, że masz
Vector
klasę iPoint
klasę. Obie przyjmująx, y
jako argumenty pozycyjne. Wyobraźmy sobie, że chcesz utworzyć funkcję, która przesuwa punkt do umieszczenia na wektorze.4 Rozwiązania
put_point_on_vec(point, vec)
Uczyń z tego metodę klasy wektorowej. na przykład
my_vec.put_point(point)
Point
klasie.my_point.put_on_vec(vec)
Vector
narzędzia__call__
, więc możesz go używać jakmy_vec_instance(point)
W rzeczywistości jest to część przykładów, nad którymi pracuję, w celu uzyskania przewodnika po metodach dunder wyjaśnionych w matematyce, które wcześniej czy później opublikuję.
Porzuciłem logikę przesunięcia samego punktu, ponieważ nie o to chodzi w tym pytaniu
źródło