Jaka jest różnica między następującymi metodami klasowymi?
Czy to jeden jest statyczny, a drugi nie?
class Test(object):
def method_one(self):
print "Called method_one"
def method_two():
print "Called method_two"
a_test = Test()
a_test.method_one()
a_test.method_two()
@classmethod
się do definicji. Pierwszy parametr powinien zostać wywołanycls
zamiastself
i otrzyma obiekt klasy, a nie instancję klasy:Test.method_three()
ia_test.method_three()
są równoważne.self
argumentu? Czy jest na to mocny przypadek użycia?Odpowiedzi:
W Pythonie istnieje rozróżnienie między metodami związanymi i niezwiązanymi .
Zasadniczo, wywołanie funkcji członka (jak
method_one
), funkcji powiązanejjest przetłumaczone na
tj. wywołanie metody niezwiązanej. Z tego powodu wywołanie do Twojej wersji
method_two
nie powiedzie się zTypeError
Możesz zmienić zachowanie metody za pomocą dekoratora
Dekorator informuje wbudowaną domyślną metaklasę
type
(klasę klasy, por. To pytanie ), aby nie tworzyła powiązanych metodmethod_two
.Teraz możesz wywoływać metodę statyczną bezpośrednio w instancji lub w klasie bezpośrednio:
źródło
Metody w Pythonie są bardzo, bardzo proste, gdy zrozumiesz podstawy systemu deskryptorów. Wyobraź sobie następującą klasę:
Teraz spójrzmy na tę klasę w powłoce:
Jak widać, jeśli uzyskasz dostęp do
foo
atrybutu klasy, otrzymasz niezwiązaną metodę, jednak wewnątrz pamięci klas (dykt) znajduje się funkcja. Dlaczego tak jest Powodem tego jest to, że klasa twojej klasy implementuje__getattribute__
deskryptory. Brzmi skomplikowanie, ale nie jest.C.foo
jest mniej więcej równoważne z tym kodem w tym szczególnym przypadku:To dlatego, że funkcje mają
__get__
metodę, która czyni je deskryptorami. Jeśli masz instancję klasy, jest ona prawie taka sama, tylko takaNone
jest instancja klasy:Dlaczego Python to robi? Ponieważ obiekt metody wiąże pierwszy parametr funkcji z instancją klasy. Stąd pochodzi jaźń. Czasami nie chcesz, aby twoja klasa uczyniła funkcję metodą, oto co
staticmethod
wchodzi w grę:staticmethod
Dekorator zawija swoją klasę i wdraża atrapę__get__
, która zwraca funkcję zawinięte w funkcji a nie jako metoda:Mam nadzieję, że to wyjaśnia.
źródło
staticmethod
Dekorator owija klasa (...) To zdanie jest nieco mylące, jako klasa, która jest owinięta jest klasa z metodąfoo
, a nie klasa, w którejfoo
jest zdefiniowana.Kiedy wywołujesz członka klasy, Python automatycznie używa odwołania do obiektu jako pierwszego parametru. Zmienna
self
tak naprawdę nic nie znaczy, to tylko konwencja kodowania. Możesz to nazwać,gargaloo
jeśli chcesz. To powiedziawszy, wywołaniemethod_two
wywołałoby aTypeError
, ponieważ Python automatycznie próbuje przekazać parametr (odwołanie do swojego obiektu nadrzędnego) do metody, która została zdefiniowana jako nie posiadająca parametrów.Aby faktycznie działało, możesz dołączyć to do definicji klasy:
lub możesz użyć
@staticmethod
dekoratora funkcji .źródło
źródło
Class.instance_method() # The class cannot use an instance method
może użyć. Wystarczy przekazać instancję ręcznie:Class.instance_method(a)
TyeError
linii.a.class_method()
, wygląda na to, żea.c
został zaktualizowany1
, więc wywołanieClass.class_method()
, zaktualizowałoClass.c
zmienną do2
. Jednak po przypisaniua.c=5
dlaczegoClass.c
nie zaktualizowano się do5
?metoda_two nie będzie działać, ponieważ definiujesz funkcję składową, ale nie mówisz jej, do której funkcji należy. Jeśli wykonasz ostatni wiersz, otrzymasz:
Jeśli definiujesz funkcje składowe dla klasy, pierwszym argumentem zawsze musi być „ja”.
źródło
Dokładne wyjaśnienie od Armin Ronacher powyżej, rozszerzając jego odpowiedzi, aby początkujący tacy jak ja dobrze to rozumieli:
Różnica w metodach zdefiniowanych w klasie, zarówno statycznych, jak i instancji (istnieje jeszcze inna metoda typu - klasa - nie omawiana tutaj, więc pomijanie jej) polega na tym, czy są one w jakiś sposób powiązane z instancją klasy, czy nie. Na przykład powiedz, czy metoda otrzymuje odwołanie do instancji klasy podczas działania
Właściwość
__dict__
Dictionary obiektu klasy zawiera odniesienie do wszystkich właściwości i metod obiektu klasy, a tym samymmetoda foo jest dostępna jak wyżej. Ważną kwestią, na którą należy tutaj zwrócić uwagę, jest to, że wszystko w Pythonie jest obiektem, a zatem odwołania w powyższym słowniku wskazują same obiekty. Nazwijmy je Obiektami własności klasy - lub CPO w zakresie mojej odpowiedzi za zwięzłość.
Jeśli deskryptor CPO jest deskryptorem, wówczas interpreter Pythona wywołuje
__get__()
metodę CPO w celu uzyskania dostępu do wartości, którą zawiera.Aby ustalić, czy CPO jest deskryptorem, interpreter Pythona sprawdza, czy implementuje protokół deskryptora. Aby wdrożyć protokół deskryptora, należy zaimplementować 3 metody
na przykład
gdzie
self
jest CPO (może to być instancja listy, str, funkcji itp.) i jest dostarczana przez środowisko wykonawczeinstance
jest instancją klasy, w której ten CPO jest zdefiniowany (obiekt „c” powyżej) i musi być dostarczony przez nas jawnośćowner
to klasa, w której zdefiniowano ten CPO (obiekt klasy „C” powyżej) i należy go dostarczyć. Jest tak jednak dlatego, że nazywamy to CPO. gdy wywołujemy go w instancji, nie musimy go podawać, ponieważ środowisko wykonawcze może dostarczyć instancję lub jej klasę (polimorfizm)value
jest zamierzoną wartością CPO i musi być przez nas dostarczonaNie wszystkie CPO są deskryptorami. Na przykład
Jest tak, ponieważ klasa listy nie implementuje protokołu deskryptora.
Zatem argument self in
c.foo(self)
jest wymagany, ponieważ jego podpis metody jest w rzeczywistości takiC.__dict__['foo'].__get__(c, C)
(jak wyjaśniono powyżej, C nie jest potrzebny, ponieważ można go znaleźć lub polimorficznie). I dlatego otrzymujesz błąd typu TypeError, jeśli nie przekażesz wymaganego argumentu instancji.Jeśli zauważysz, że do metody nadal odwołuje się obiekt klasy C, a powiązanie z instancją klasy jest osiągane poprzez przekazanie kontekstu w postaci obiektu instancji do tej funkcji.
Jest to całkiem niesamowite, ponieważ jeśli zdecydujesz się nie utrzymywać kontekstu ani powiązania z instancją, wystarczyło napisać klasę, aby owinąć CPO deskryptora i zastąpić jej
__get__()
metodę, aby nie wymagała kontekstu. Ta nowa klasa nazywana jest dekoratorem i jest stosowana za pomocą słowa kluczowego@staticmethod
Brak kontekstu w nowym opakowanym CPO
foo
nie generuje błędu i można to zweryfikować w następujący sposób:Przypadek użycia metody statycznej jest bardziej przestrzenią nazw i utrzymywalnością kodu (usunięcie go z klasy i udostępnienie w całym module itp.).
Może lepiej jest pisać metody statyczne niż metody instancji, o ile to możliwe, chyba że oczywiście trzeba kontekstualizować metody (takie jak zmienne instancji dostępu, zmienne klas itp.). Jednym z powodów jest ułatwienie wyrzucania elementów bezużytecznych przez niepotrzebne odwoływanie się do obiektów.
źródło
to jest błąd.
po pierwsze, pierwsza linia powinna być taka (uważaj na wielkie litery)
Ilekroć wywołujesz metodę klasy, staje się ona pierwszym argumentem (stąd nazwa self), a metoda_two podaje ten błąd
źródło
Drugi nie zadziała, ponieważ gdy wywołasz go w ten sposób, python wewnętrznie próbuje wywołać go z instancją a_test jako pierwszym argumentem, ale twoja metoda_two nie przyjmuje żadnych argumentów, więc nie będzie działać, otrzymasz środowisko wykonawcze błąd. Jeśli chcesz ekwiwalent metody statycznej, możesz użyć metody klasy. Metody klas w Pythonie są znacznie mniejsze niż metody statyczne w językach takich jak Java lub C #. Najczęściej najlepszym rozwiązaniem jest użycie metody w module, poza definicją klasy, która działa wydajniej niż metoda klasy.
źródło
Class Test(object): @staticmethod def method_two(): print(“called method_two”)
Jednym z przypadków użycia, o którym myślałem, było to, że chcesz, aby funkcja była częścią klasy, ale nie chcesz, aby użytkownik miał bezpośredni dostęp do funkcji. Więcmethod_two
mogą być wywoływane przez inne funkcje wewnątrzTest
instancji, ale nie mogą być wywoływane za pomocąa_test.method_two()
. Jeśli użyjędef method_two()
, czy to zadziała w tym przypadku użycia? Czy jest lepszy sposób modyfikacji definicji funkcji, więc działa ona zgodnie z przeznaczeniem dla powyższego przypadku użycia?Wywołanie metody method_two spowoduje zgłoszenie wyjątku z powodu nieakceptowania parametru własnego, który środowisko wykonawcze Python automatycznie przekaże.
Jeśli chcesz utworzyć metodę statyczną w klasie Python, udekoruj ją za pomocą
staticmethod decorator
.źródło
Proszę przeczytać ten dokument z Pierwszej Klasy Guido wszystko Wyraźnie wyjaśniło, w jaki sposób powstają metody Unbound, Bound.
źródło
Definicja
method_two
jest nieprawidłowa. Kiedy zadzwoniszmethod_two
, dostanieszTypeError: method_two() takes 0 positional arguments but 1 was given
od tłumacza.Metoda instancji jest funkcją ograniczoną, gdy ją wywołujesz
a_test.method_two()
. Automatycznie przyjmujeself
, co wskazuje na wystąpienieTest
, jako swój pierwszy parametr. Za pomocąself
parametru metoda instancji może swobodnie uzyskiwać dostęp do atrybutów i modyfikować je w tym samym obiekcie.źródło
Metody niezwiązane
Metody niezwiązane to metody, które nie są jeszcze powiązane z żadną konkretną instancją klasy.
Metody powiązane
Metody powiązane to te, które są powiązane z konkretnym wystąpieniem klasy.
Jak tu udokumentowano , self może odnosić się do różnych rzeczy w zależności od funkcji jest związana, niezwiązana lub statyczna.
Spójrz na następujący przykład:
Ponieważ nie użyliśmy instancji klasy
obj
- przy ostatnim wywołaniu możemy powiedzieć, że wygląda jak metoda statyczna.Jeśli tak, to jaka jest różnica między
MyClass.some_method(10)
wywołaniem a wywołaniem funkcji statycznej ozdobionej@staticmethod
dekoratorem?Korzystając z dekoratora, wyraźnie zaznaczamy, że metoda zostanie użyta bez uprzedniego utworzenia dla niej instancji. Zwykle nie można oczekiwać, że metody członków klasy będą używane bez instancji, a dostęp do nich może powodować ewentualne błędy w zależności od struktury metody.
Dodając
@staticmethod
dekorator, umożliwiamy również dostęp do obiektu.Nie możesz zrobić powyższego przykładu metodami instancji. Możesz przetrwać pierwszy (tak jak poprzednio), ale drugi zostanie przetłumaczony na niezwiązane wywołanie,
MyClass.some_method(obj, 10)
które podniesie,TypeError
ponieważ metoda instancji przyjmuje jeden argument i nieumyślnie próbujesz przekazać dwa.Następnie możesz powiedzieć: „jeśli mogę wywoływać metody statyczne zarówno przez instancję, jak i klasę,
MyClass.some_static_method
iMyClass().some_static_method
powinny to być te same metody”. Tak!źródło
Metoda powiązana = metoda instancji
Metoda niezwiązana = metoda statyczna.
źródło