Jaka jest różnica między funkcją ozdobione @staticmethod
i jeden ozdobione @classmethod
?
python
oop
methods
python-decorators
Daryl Spitzer
źródło
źródło
Odpowiedzi:
Może trochę kodu przykładu pomoże: Zauważ różnicę w podpisach pożarowych
foo
,class_foo
orazstatic_foo
:Poniżej znajduje się zwykły sposób, w jaki instancja obiektu wywołuje metodę. Instancja obiektu
a
, jest domyślnie przekazywana jako pierwszy argument.W przypadku metod klasy klasa instancji obiektu jest domyślnie przekazywana jako pierwszy argument zamiast
self
.Możesz także zadzwonić
class_foo
za pomocą klasy. W rzeczywistości, jeśli zdefiniujesz coś jako metodę klasy, prawdopodobnie dzieje się tak dlatego, że zamierzasz wywoływać to z klasy, a nie z instancji klasy.A.foo(1)
zgłosiłby błąd typu TypeError, aleA.class_foo(1)
działa dobrze:Jednym z zastosowań, które ludzie znaleźli dla metod klasowych, jest tworzenie dziedziczonych alternatywnych konstruktorów .
W przypadku metod statycznych ani
self
(instancja obiektu), anicls
(klasa) nie są domyślnie przekazywane jako pierwszy argument. Zachowują się jak zwykłe funkcje, tyle że można je wywoływać z instancji lub klasy:Metody statyczne są używane do grupowania funkcji, które mają pewne logiczne połączenie z klasą do klasy.
foo
jest po prostu funkcją, ale kiedy wywołujesza.foo
, nie dostajesz po prostu funkcji, dostajesz „częściowo zastosowaną” wersję funkcji z instancją obiektua
związaną jako pierwszy argument funkcji.foo
oczekuje 2 argumentów, aa.foo
tylko 1 argument.a
jest związany zfoo
. Oto, co należy rozumieć pod pojęciem „związany” poniżej:Dzięki
a.class_foo
,a
nie jest związanyclass_foo
, a klasaA
jest związanaclass_foo
.Tutaj przy pomocy metody statycznej, mimo że jest to metoda,
a.static_foo
zwraca po prostu dobrą funkcję „ole” bez żadnych argumentów.static_foo
oczekuje 1 argumentu ia.static_foo
oczekuje również 1 argumentu.I oczywiście to samo dzieje się, gdy zamiast tego dzwonisz
static_foo
do klasyA
.źródło
@staticmethod
może pomóc uporządkować kod, zastępując go podklasami. Bez niego warianty funkcji będą się unosić w przestrzeni nazw modułów.@staticmethod
- możesz go użyć, aby usunąć cruft. Wdrażam język programowania w Pythonie - funkcje zdefiniowane w bibliotece używająexecute
metody statycznej , w której funkcje zdefiniowane przez użytkownika wymagają argumentów instancji (tj. Treści funkcji). Ten dekorator eliminuje ostrzeżenia „nieużywanego parametru” w inspektorze PyCharm.Staticmethod jest metodą, która nie wie nic na temat klasy lub instancji był nazywany dalej. Dostaje tylko argumenty, które zostały przekazane, bez domyślnego pierwszego argumentu. Jest to w zasadzie bezużyteczne w Pythonie - możesz po prostu użyć funkcji modułu zamiast metody static.
Classmethod , z drugiej strony, jest to metoda, która zostaje przekazana klasę Nazwano na lub klasę instancji był nazywany dalej, jako pierwszy argument. Jest to przydatne, gdy chcesz, aby metoda była fabryką dla klasy: ponieważ pobiera rzeczywistą klasę, do której została wywołana, jako pierwszy argument, zawsze możesz utworzyć odpowiednią klasę, nawet jeśli w grę wchodzą podklasy. Obserwuj na przykład, w jaki
dict.fromkeys()
sposób metoda klasy zwraca instancję podklasy po wywołaniu w podklasie:źródło
Zasadniczo
@classmethod
tworzy metodę, której pierwszym argumentem jest klasa, z której została wywołana (a nie instancja klasy),@staticmethod
nie ma żadnych domyślnych argumentów.źródło
Oficjalne dokumenty Pythona:
@classmethod
@staticmethod
źródło
Oto krótki artykuł na ten temat
źródło
Aby zdecydować, czy użyć @staticmethod czy @classmethod , musisz zajrzeć do swojej metody. Jeśli twoja metoda uzyskuje dostęp do innych zmiennych / metod w twojej klasie, użyj @classmethod . Z drugiej strony, jeśli twoja metoda nie dotyka żadnych innych części klasy, użyj @staticmethod.
źródło
cls._counter
nadal będzie,cls._counter
nawet jeśli kod zostanie umieszczony w innej klasie lub nazwa klasy zostanie zmieniona.Apple._counter
jest specyficzny dlaApple
klasy; dla innej klasy lub gdy nazwa klasy zostanie zmieniona, należy zmienić klasę odniesienia.Być może widziałeś kod Pythona, taki jak ten pseudokod, który demonstruje sygnatury różnych typów metod i udostępnia dokumentację wyjaśniającą każdy z nich:
Metoda wystąpienia normalnego
Najpierw wyjaśnię
a_normal_instance_method
. Jest to dokładnie nazywane „ metodą instancji ”. Gdy używana jest metoda instancji, jest ona używana jako funkcja częściowa (w przeciwieństwie do funkcji całkowitej, zdefiniowanej dla wszystkich wartości podczas przeglądania w kodzie źródłowym), która, gdy jest używana, pierwszy z argumentów jest predefiniowana jako instancja obiekt ze wszystkimi podanymi atrybutami. Jest z nim związana instancja obiektu i musi być wywołana z instancji obiektu. Zwykle uzyskuje dostęp do różnych atrybutów instancji.Na przykład jest to instancja ciągu:
jeśli użyjemy metody instancji
join
na tym ciągu, aby dołączyć do innej iterowalnej, jest to oczywiście funkcja instancji, oprócz tego, że jest funkcją listy iterowalnej['a', 'b', 'c']
:Metody powiązane
Metody instancji można powiązać za pomocą wyszukiwania przerywanego do późniejszego użycia.
Na przykład wiąże to
str.join
metodę z':'
instancją:Później możemy użyć tego jako funkcji, która ma już przypisany pierwszy argument. W ten sposób działa jak funkcja częściowa w instancji:
Metoda statyczna
Metoda statyczna nie przyjmuje instancji jako argumentu.
Jest bardzo podobny do funkcji na poziomie modułu.
Jednak funkcja poziomu modułu musi znajdować się w module i być specjalnie importowana do innych miejsc, w których jest używana.
Jednak jeśli jest on dołączony do obiektu, będzie wygodnie podążał za obiektem również poprzez importowanie i dziedziczenie.
Przykładem metody statycznej jest
str.maketrans
przeniesienie zstring
modułu w Pythonie 3. To sprawia, że tabela translacji nadaje się do użycia przezstr.translate
. Wydaje się dość głupie, gdy jest używane z instancji ciągu, jak pokazano poniżej, ale importowanie funkcji zstring
modułu jest raczej niezdarne i fajnie jest móc wywoływać ją z klasy, jak wstr.maketrans
W Pythonie 2 musisz zaimportować tę funkcję z coraz mniej użytecznego modułu łańcuchowego:
Metoda klasowa
Metoda klasy jest podobna do metody instancji, ponieważ przyjmuje domyślny pierwszy argument, ale zamiast przejmować instancję, bierze klasę. Często są one używane jako alternatywne konstruktory dla lepszego wykorzystania semantycznego i będą wspierać dziedziczenie.
Najbardziej kanonicznym przykładem wbudowanej metody klasy jest
dict.fromkeys
. Jest używany jako alternatywny konstruktor dict (dobrze nadaje się, gdy wiesz, jakie są twoje klucze i chcesz dla nich wartość domyślną).Kiedy dyktujemy podklasę, możemy użyć tego samego konstruktora, który tworzy instancję podklasy.
Zobacz kod źródłowy pandy dla innych podobnych przykładów alternatywnych konstruktorów, a także oficjalną dokumentację Pythona na temat
classmethod
istaticmethod
.źródło
Zacząłem uczyć się języka programowania w C ++, potem w Javie, a potem w Pythonie, więc to pytanie również mnie bardzo niepokoiło, dopóki nie zrozumiałem prostego użycia każdego z nich.
Metoda klasy: Python w przeciwieństwie do Java i C ++ nie ma przeciążenia konstruktora. Aby to osiągnąć, możesz użyć
classmethod
. Poniższy przykład to wyjaśniRozważmy mamy
Person
klasę która przyjmuje dwa argumentyfirst_name
alast_name
i tworzy instancjęPerson
.Jeśli wymaganie pojawi się wtedy, gdy musisz utworzyć klasę używając tylko jednej nazwy, po prostu
first_name
nie możesz zrobić czegoś takiego w Pythonie.Spowoduje to błąd podczas próby utworzenia obiektu (instancji).
Można jednak osiągnąć to samo,
@classmethod
jak wspomniano poniżejMetoda statyczna: jest to dość proste, nie jest powiązane z instancją ani klasą i można to po prostu wywołać za pomocą nazwy klasy.
Powiedzmy, że w powyższym przykładzie potrzebujesz walidacji, która
first_name
nie powinna przekraczać 20 znaków, możesz to po prostu zrobić.i możesz po prostu zadzwonić za pomocą
class name
źródło
def __init__(self, first_name, last_name="")
zamiast metody klasowejget_person
. Również wynik będzie dokładnie taki sam w tym przypadku.Wydaje mi się, że lepszym pytaniem jest „Kiedy użyłbyś @classmethod vs. @staticmethod?”
@classmethod pozwala na łatwy dostęp do prywatnych członków powiązanych z definicją klasy. jest to świetny sposób na tworzenie singletonów lub istnieją klasy fabryczne, które kontrolują liczbę instancji tworzonych obiektów.
@staticmethod zapewnia marginalny wzrost wydajności, ale nie widziałem jeszcze produktywnego zastosowania metody statycznej w klasie, której nie można byłoby uzyskać jako samodzielnej funkcji poza klasą.
źródło
W Pythonie 2.4 dodano @dekoratory. Jeśli używasz Pythona <2.4, możesz użyć funkcji classmethod () i staticmethod ().
Na przykład, jeśli chcesz utworzyć metodę fabryczną (funkcja zwracająca instancję innej implementacji klasy w zależności od otrzymanego argumentu), możesz zrobić coś takiego:
Zauważ również, że jest to dobry przykład użycia metody klasy i metody statycznej. Metoda statyczna wyraźnie należy do klasy, ponieważ korzysta ona wewnętrznie z Klastra klas. Metoda klasy potrzebuje tylko informacji o klasie, a nie instancji obiektu.
Kolejną zaletą przekształcenia
_is_cluster_for
metody w metodę klasy jest to, że podklasa może zdecydować o zmianie implementacji, być może dlatego, że jest dość ogólna i może obsługiwać więcej niż jeden typ klastra, więc samo sprawdzenie nazwy klasy nie wystarczy.źródło
Metody statyczne:
Korzyści z metod statycznych:
Wygodniej jest importować niż funkcje na poziomie modułu, ponieważ każda metoda nie musi być specjalnie importowana
Metody klasowe:
Są one tworzone za pomocą wbudowanej funkcji classmethod.
źródło
@staticmethod
po prostu wyłącza domyślną funkcję jako deskryptor metody. classmethod zawija twoją funkcję w wywoływalny kontener, który jako pierwszy argument przekazuje odwołanie do klasy będącej właścicielem:W rzeczywistości
classmethod
ma narzut związany ze środowiskiem uruchomieniowym, ale umożliwia dostęp do klasy będącej właścicielem. Alternatywnie polecam użycie metaklasy i umieszczenie klasowych metod na tej metaklasie:źródło
c = C(); c.foo()
podnosi AttributeError, musisz zrobićtype(c).foo()
. Może to być również uważane za cechę - nie mogę jednak wymyślić, dlaczego chcesz.Ostateczny przewodnik na temat używania metod statycznych, klasowych lub abstrakcyjnych w Pythonie jest dobrym linkiem do tego tematu i podsumowano go następująco.
@staticmethod
funkcja jest niczym więcej niż funkcją zdefiniowaną w klasie. Można to wywoływać bez wcześniejszego tworzenia klasy. Jego definicja jest niezmienna przez dziedziczenie.@classmethod
funkcja może być również wywoływana bez tworzenia instancji klasy, ale jej definicja jest następująca Podklasa, a nie klasa nadrzędna, poprzez dziedziczenie, może zostać zastąpiona przez podklasę. Jest tak, ponieważ pierwszym argumentem@classmethod
funkcji musi zawsze być cls (klasa).źródło
Różni się tylko pierwszy argument :
Bardziej szczegółowo...
normalna metoda
Gdy wywoływana jest metoda obiektu, automatycznie otrzymuje dodatkowy argument
self
jako pierwszy argument. To znaczy metodanależy wywołać z 2 argumentami.
self
jest automatycznie przekazywany i jest to sam obiekt .metoda klasowa
Kiedy metoda jest udekorowana
automatycznie podawanym argumentem nie jest
self
, ale klasaself
.metoda statyczna
Kiedy metoda jest udekorowana
metoda nie otrzymuje żadnego automatycznego argumentu. Podano tylko parametry, z którymi jest wywoływany.
zastosowania
classmethod
jest najczęściej używany do alternatywnych konstruktorów.staticmethod
nie używa stanu obiektu. Może to być funkcja zewnętrzna w stosunku do klasy. Umieszcza tylko wewnątrz klasy dla grupowania funkcji o podobnej funkcjonalności (na przykład, jakMath
metody statyczne klasy Java )źródło
Pozwól mi najpierw powiedzieć podobieństwo między metodą ozdobioną @classmethod a @staticmethod.
Podobieństwo: oba można wywoływać w samej klasie , a nie tylko w instancji klasy. Oba są więc w pewnym sensie metodami klasy .
Różnica: Metoda klasy otrzyma samą klasę jako pierwszy argument, podczas gdy metoda statyczna nie.
Zatem metoda statyczna nie jest, w pewnym sensie, związana z samą klasą i po prostu wisi w niej tylko dlatego, że może mieć powiązaną funkcjonalność.
źródło
Innym aspektem dotyczącym metody statycznej vs metody klasowej jest dziedziczenie. Powiedz, że masz następującą klasę:
A następnie chcesz zastąpić
bar()
w klasie podrzędnej:To działa, ale zauważ, że teraz
bar()
implementacja w klasie potomnej (Foo2
) nie może już korzystać z niczego specyficznego dla tej klasy. Na przykład powiedzmyFoo2
miał metodę o nazwiemagic()
, której chcesz użyć wFoo2
implementacjibar()
:Rozwiązaniem tutaj byłoby zadzwonić
Foo2.magic()
wbar()
, ale to jesteś powtarzając sobie (jeśli nazwaFoo2
zmian, trzeba pamiętać, aby zaktualizować tębar()
metodę).Dla mnie jest to niewielkie naruszenie zasady otwartego / zamkniętego , ponieważ podjęta decyzja
Foo
ma wpływ na twoją zdolność do refaktoryzacji wspólnego kodu w klasie pochodnej (tj. Jest mniej otwarta na rozszerzenie). Gdybyśmybar()
byli wclassmethod
porządku:Daje:
In Foo2 MAGIC
źródło
Spróbuję wyjaśnić podstawową różnicę na przykładzie.
1 - możemy bezpośrednio wywoływać metody statyczne i klasowe bez inicjalizacji
2- Metoda statyczna nie może wywoływać metody self, ale może wywoływać inną metodę statyczną i klasową
3- Metoda statyczna należy do klasy i w ogóle nie będzie używać obiektu.
Metoda 4- klasy nie jest związana z obiektem, ale z klasą.
źródło
@classmethod: może zostać użyty do stworzenia wspólnego globalnego dostępu do wszystkich instancji utworzonych dla tej klasy ..... jak np. aktualizacja rekordu przez wielu użytkowników .... W szczególności uznałem, że jest on użyteczny przy tworzeniu singletonów ...: )
Metoda @static: nie ma nic wspólnego z klasą lub instancją powiązaną z ... ale dla czytelności można użyć metody statycznej
źródło
Warto rozważyć różnicę między:
i
Zmieniło się to między python2 i python3:
python2:
python3:
Tak więc używanie
@staticmethod
metod wywoływanych tylko bezpośrednio z klasy stało się opcjonalne w python3. Jeśli chcesz wywoływać je zarówno z klasy, jak i instancji, nadal musisz użyć@staticmethod
dekoratora.Pozostałe przypadki zostały dobrze uwzględnione w odpowiedzi Unutbus.
źródło
Metoda klasy odbiera klasę jako domyślny pierwszy argument, podobnie jak metoda instancji odbiera instancję. Jest to metoda powiązana z klasą, a nie z obiektem klasy. Ma ona dostęp do stanu klasy, ponieważ przyjmuje parametr klasy wskazujący na klasę, a nie na instancję obiektu. Może modyfikować stan klasy, który obowiązywałby we wszystkich instancjach klasy. Na przykład może modyfikować zmienną klasy, która będzie obowiązywać dla wszystkich instancji.
Z drugiej strony metoda statyczna nie otrzymuje domyślnego pierwszego argumentu w porównaniu do metod klasowych lub instancji. I nie może uzyskać dostępu ani modyfikować stanu klasy. Należy tylko do klasy, ponieważ z punktu widzenia projektowania jest to właściwy sposób. Ale pod względem funkcjonalności nie jest związana w czasie wykonywania z klasą.
jako wytyczne, użyj metod statycznych jako narzędzi, użyj metod klasowych, na przykład fabrycznie. A może zdefiniować singletona. I użyj metod instancji do modelowania stanu i zachowania instancji.
Mam nadzieję, że było jasne!
źródło
Mój wkład pokazuje różnicę wśród
@classmethod
,@staticmethod
oraz metody instancji, w tym jak instancja może pośrednio wywołać@staticmethod
. Ale zamiast pośrednio wywoływać a@staticmethod
z instancji, uczynienie go prywatnym może być bardziej „pytoniczne”. Zdobycie czegoś z prywatnej metody nie zostało tutaj wykazane, ale jest to w zasadzie ta sama koncepcja.źródło
Metody klasowe, jak sama nazwa wskazuje, służą do wprowadzania zmian do klas, a nie obiektów. Aby wprowadzić zmiany w klasach, zmodyfikują atrybuty klas (nie atrybuty obiektowe), ponieważ w ten sposób aktualizujesz klasy. To jest powód, dla którego metody klasowe przyjmują klasę (konwencjonalnie oznaczoną przez „cls”) jako pierwszy argument.
Z drugiej strony metody statyczne są wykorzystywane do wykonywania funkcji, które nie są związane z klasą, tj. Nie odczytują ani nie zapisują zmiennych klas. Stąd metody statyczne nie przyjmują klas jako argumentów. Są one używane, aby klasy mogły wykonywać funkcje niezwiązane bezpośrednio z celem klasy.
źródło
Analizuj @staticmethod dosłownie dostarczając różnych informacji.
Normalna metoda klasy jest domyślną metodą dynamiczną , która przyjmuje instancję jako pierwszy argument.
W przeciwieństwie do tego metoda statyczna nie przyjmuje instancji jako pierwszego argumentu, dlatego nazywa się ją „statyczna” .
Metoda statyczna jest rzeczywiście taką normalną funkcją, jak te poza definicją klasy.
Na szczęście jest zgrupowane w klasie tylko po to, aby stać bliżej miejsca zastosowania lub możesz przewinąć, aby go znaleźć.
źródło
Myślę, że dając czysto Pythonową wersję
staticmethod
iclassmethod
pomoże zrozumieć różnicę między nimi na poziomie języka.Oba są deskryptorami innymi niż dane (łatwiej byłoby je zrozumieć, jeśli najpierw znasz deskryptory ).
źródło
staticmethod nie ma dostępu do atrybutów obiektu, klasy ani klas nadrzędnych w hierarchii dziedziczenia. Można go wywołać bezpośrednio w klasie (bez tworzenia obiektu).
classmethod nie ma dostępu do atrybutów obiektu. Może jednak uzyskać dostęp do atrybutów klasy i klas nadrzędnych w hierarchii dziedziczenia. Można go wywołać bezpośrednio w klasie (bez tworzenia obiektu). Wywołany w obiekcie jest taki sam, jak normalna metoda, która nie
self.<attribute(s)>
uzyskuje dostępu i dostępuself.__class__.<attribute(s)>
tylko .Pomyśl, że mamy klasę
b=2
, stworzymy obiekt i ponownie w nim ustawimyb=4
. Metoda statyczna nie ma dostępu do niczego z poprzedniego. Classmethod może uzyskać dostęp.b==2
tylko poprzezcls.b
. Normalna metoda może uzyskać dostęp zarówno:.b==4
przez, jakself.b
i.b==2
przezself.__class__.b
.Możemy postępować zgodnie ze stylem KISS (upraszczając, głupio): nie używaj metod static i metod, nie używaj klas bez ich tworzenia, uzyskuj dostęp tylko do atrybutów obiektu
self.attribute(s)
. Istnieją języki, w których OOP jest wdrażany w ten sposób i myślę, że nie jest to zły pomysł. :)źródło
Szybki hack innych identycznych metod w iPython ujawnia, że
@staticmethod
daje marginalny wzrost wydajności (w nanosekundach), ale poza tym wydaje się, że nie spełnia żadnej funkcji. Ponadto wszelkie przyrosty wydajności zostaną prawdopodobnie usunięte przez dodatkowe prace związane z przetwarzaniem metodystaticmethod()
podczas kompilacji (co dzieje się przed wykonaniem kodu po uruchomieniu skryptu).Ze względu na czytelność kodu unikałbym,
@staticmethod
chyba że twoja metoda zostanie wykorzystana do prac, w których liczą się nanosekundy.źródło