Co to są „metody klasowe” i „metody instancji” w Pythonie?

37

Na czacie odbyła się dyskusja związana z pytaniem (samo pytanie nie ma znaczenia dla tego pytania), które ujawniło, że mogę nie znać Pythona.

Moim zdaniem, mimo że terminologia różni się w zależności od języka, ogólnie możemy klasyfikować funkcje jako:

  • [darmowe] funkcje
  • metody statyczne / funkcje członka statycznego
  • metody niestatyczne / niestatyczne funkcje składowe

Najwyraźniej w Pythonie istnieje inny rodzaj funkcji, która nie pasuje do powyższych kategorii, która jest metodą, ale „nie zna swojej klasy”.

Co to są „metody klas” i „metody instancji” w Pythonie?

Lekkość Wyścigi z Moniką
źródło
1
Jeśli ktoś jest zainteresowany dyskusją na czacie, zacznij tutaj: chat.stackexchange.com/transcript/message/26479002#26479002
yannis
1
IMO lepszej odpowiedzi udziela inna strona stackexchange
Trevor Boyd Smith
FYI link znajduje się na dole akceptowanego ... ale myślę, że wiele osób nie zauważy linku lub nigdy go nie dostanie, więc skopiowałem go tutaj.
Trevor Boyd Smith

Odpowiedzi:

49

Krótka odpowiedź

  • metoda instancji zna jej instancję (a tym samym jej klasę)
  • metoda klasy zna swoją klasę
  • metoda statyczna nie zna swojej klasy ani instancji

Długa odpowiedź

Metody klasowe

Metoda klasa to taka, która należy do grupy jako całości. Nie wymaga instancji. Zamiast tego klasa zostanie automatycznie wysłana jako pierwszy argument. Metodę klasy deklaruje się za pomocą @classmethoddekoratora.

Na przykład:

class Foo(object):
    @classmethod
    def hello(cls):
        print("hello from %s" % cls.__name__)
Foo.hello()
-> "Hello from Foo"
Foo().hello()
-> "Hello from Foo"

Metody instancji

Z drugiej strony metoda instancji wymaga instancji w celu jej wywołania i nie wymaga dekoratora. Jest to zdecydowanie najpopularniejszy rodzaj metody.

class Foo(object):
    def hello(self):
        print("hello from %s" % self.__class__.__name__)
Foo.hello()
-> TypeError: hello() missing 1 required positional argument: 'self'

(uwaga: powyższe dotyczy python3; w python2 pojawi się nieco inny błąd)

Metody statyczne

Statyczna metoda jest podobna do metody klasy, ale nie dostanie obiekt klasy jako automatyczny parametru. Jest tworzony przy użyciu @staticmethoddekoratora.

class Foo(object):
    @staticmethod
    def hello(cls):
        print("hello from %s" % cls.__name__)

Foo.hello()
-> TypeError: hello() missing 1 required positional argument: 'cls'

Linki do dokumentacji

Oto linki do odpowiedniej dokumentacji Python3:

Dokumentacja modelu danych mówi o różnicy między metodami klasowymi a metodami statycznymi:

Obiekty metod statycznych Obiekty metod statycznych umożliwiają pokonanie transformacji obiektów funkcyjnych w obiekty metodalne opisane powyżej. Statyczny obiekt metody jest opakowaniem wokół dowolnego innego obiektu, zwykle obiektu metody zdefiniowanego przez użytkownika. Gdy obiekt metody statycznej jest pobierany z klasy lub instancji klasy, faktycznie zwracany obiekt jest opakowanym obiektem, który nie podlega dalszej transformacji. Obiekty metodą statyczną nie są same w sobie możliwe do wywołania, chociaż zwykle są to obiekty, które owijają. Obiekty metody statycznej są tworzone przez wbudowany konstruktor staticmethod ().

Obiekty metody klasy Obiekt metody klasy, podobnie jak statyczny obiekt metody, to opakowanie otaczające inny obiekt, który zmienia sposób pobierania tego obiektu z klas i instancji klas. Zachowanie obiektów metod klasy podczas takiego wyszukiwania opisano powyżej w części „Metody zdefiniowane przez użytkownika”. Obiekty metod klasy są tworzone przez wbudowany konstruktor classmethod ().

Powiązane pytania

Bryan Oakley
źródło
4
@LightnessRacesinOrbit: Nie sądzę, aby metody statyczne były używane szczególnie często w pythonie. Używając mojego systemu jako przypadkowej próbki, kiedy przeszukuję wszystkie zainstalowane pakiety, tylko około 1% wszystkich metod to metody statyczne (co szczerze mówiąc było więcej, niż się spodziewałem).
Bryan Oakley
1
„Metody statyczne” są zwykle zapachem kodu i odradza je np. Przewodnik po stylu Python Gogole.
9000
3
Myślę, że odpowiedź byłaby lepsza, gdyby zwróciła uwagę na podklasy, w których metody klasowe są przydatne.
Winston Ewert,
1
@ user2357112: Po prostu policzyłem wszystkie wystąpienia "^ def(", a następnie policzyłem wszystkie wystąpienia @staticmethod. Bardzo nienaukowy, ale prawdopodobnie był na boisku.
Bryan Oakley
2
@Kashyap: TL; DR dotyczy pierwszego akapitu. Myślę, że działa lepiej u góry niż u dołu.
Bryan Oakley
8

Co to są „metody klasowe” i „metody instancji” w Pythonie?

  • „Metoda instancji” wykorzystuje informacje zawarte w instancji, aby dowiedzieć się, jaką wartość zwrócić (lub jaki efekt uboczny zrobić). Te są bardzo częste.

  • „Metoda klasy” wykorzystuje informacje o klasie (a nie instancji tej klasy), aby wpływać na to, co ona robi (są one zwykle używane do tworzenia nowych instancji jako alternatywnych konstruktorów, a zatem nie są niewiarygodnie powszechne).

  • „Metoda statyczna” nie wykorzystuje żadnych informacji o klasie lub instancji do obliczenia tego, co robi. Zwykle jest w klasie dla wygody. (Jako takie też nie są zbyt częste.)

Funkcja X

Pamiętasz klasę matematyczną: „y jest funkcją x f(x),?” Zastosujmy to w kodzie:

y = function(x)

Z powyższego wynika, że ​​ponieważ xmoże się zmienić, ymoże ulec zmianie, gdy xzmiany. To właśnie ma na myśli, gdy mówimy, że „ yjest funkcją x

Co będzie ykiedy zbędzie 1? 2? 'FooBarBaz'?

ynie jest funkcją z, więc zmoże być czymkolwiek i nie wpływać na wynik funkcji, zakładając, że nasza functionjest funkcją czystą. (Jeśli uzyskuje dostęp zjako zmienna globalna, to nie jest to czysta funkcja - właśnie to oznacza funkcjonalna czystość.)

Pamiętaj o powyższym, czytając następujące opisy:

Metody instancji

Metoda wystąpienie jest funkcją jest funkcja o wystąpieniu . Funkcja przyjmuje instancję domyślnie jako argument, a instancja jest używana przez funkcję do określenia wyniku funkcji.

Wbudowanym przykładem metody instancji jest str. Niższy:

>>> 'ABC'.lower()
'abc'

str.lower jest wywoływany w wystąpieniu ciągu i wykorzystuje informacje zawarte w wystąpieniu, aby dowiedzieć się, który nowy ciąg zwrócić.

Metody klasowe:

Pamiętaj, że w Pythonie wszystko jest przedmiotem. Oznacza to, że klasa jest obiektem i może być przekazana jako argument funkcji.

Metoda klasy jest funkcją, która jest funkcją z klasy . Akceptuje klasę jako argument.

Wbudowanym przykładem jest dict.fromkeys:

>>> dict.fromkeys('ABC')
{'C': None, 'B': None, 'A': None}

Funkcja niejawnie zna swoją klasę, funkcja wykorzystuje klasę do wpływania na wynik funkcji i tworzy nową klasę z iterowalnego. OragedDict pokazuje to, używając tej samej metody:

>>> from collections import OrderedDict
>>> OrderedDict.fromkeys('ABC')
OrderedDict([('A', None), ('B', None), ('C', None)])

Metoda class wykorzystuje informacje o klasie (a nie instancji tej klasy), aby wpłynąć na typ klasy, który ma zostać zwrócony.

Metody statyczne

Wspominasz o metodzie, która „nie zna swojej klasy” - jest to metoda statyczna w Pythonie. Jest on jedynie dołączony dla wygody do obiektu klasy. Opcjonalnie może to być osobna funkcja w innym module, ale jej sygnatura wywołania byłaby taka sama.

Metoda statyczna nie jest funkcją klasy ani obiektu.

Wbudowanym przykładem metody statycznej jest str.maketrans z Python 3.

>>> str.maketrans('abc', 'bca')
{97: 98, 98: 99, 99: 97}

Biorąc pod uwagę kilka argumentów, tworzy słownik, który nie jest funkcją jego klasy.

Jest to wygodne, ponieważ strjest zawsze dostępne w globalnej przestrzeni nazw, więc możesz łatwo używać go z funkcją translacji:

>>> 'abracadabra'.translate(str.maketrans('abc', 'bca'))
'bcrbabdbcrb'

W Pythonie 2 musisz uzyskać do niego dostęp z stringmodułu:

>>> 'abracadabra'.translate(str.maketrans('abc', 'bca'))
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: type object 'str' has no attribute 'maketrans'
>>> import string
>>> 'abracadabra'.translate(string.maketrans('abc', 'bca'))
'bcrbabdbcrb'

Przykład

class AClass(object):
    """In Python, a class may have several types of methods: 
    instance methods, class methods, and static methods
    """

    def an_instance_method(self, x, y, z=None):
        """this is a function of the instance of the object
        self is the object's instance
        """
        return self.a_class_method(x, y)

    @classmethod
    def a_class_method(cls, x, y, z=None):
        """this is a function of the class of the object
        cls is the object's class
        """
        return cls.a_static_method(x, y, z=z)

    @staticmethod
    def a_static_method(x, y, z=None):
        """this is neither a function of the instance or class to 
        which it is attached
        """
        return x, y, z

Utwórzmy instancję:

>>> instance = AClass()

Teraz instancja może wywoływać wszystkie metody:

>>> instance.an_instance_method('x', 'y')
('x', 'y', None)
>>> instance.a_static_method('x', 'y')
('x', 'y', None)
>>> instance.a_class_method('x', 'y')
('x', 'y', None)

Ale klasa zwykle nie jest przeznaczona do wywoływania metody instancji, chociaż oczekuje się, że wywoła inne:

>>> AClass.a_class_method('x', 'y')
('x', 'y', None)
>>> AClass.a_static_method('x', 'y')
('x', 'y', None)
>>> AClass.an_instance_method('x', 'y')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: an_instance_method() missing 1 required positional argument: 'y'

Trzeba jawnie przekazać instancję, aby wywołać metodę instancji:

>>> AClass.an_instance_method(instance, 'x', 'y')
('x', 'y', None)
Aaron Hall
źródło
„w Pythonie jest to metoda statyczna. Jest ona jedynie dołączona dla wygody do obiektu klasy. Opcjonalnie może to być osobna funkcja w innym module, ale jej sygnatura wywołania byłaby taka sama”. Wydaje się bardziej mylące niż wygodne. Dlaczego miałbyś przypisywać funkcję do klasy, jeśli jej ciało nie będzie miało pojęcia o tej klasie.
Wyścigi lekkości z Monicą
@LightnessRacesinOrbit Opracowałem każdy punkt
Aaron Hall
Osobiście zawsze patrzyłem na to, że metoda instancji jest operacją na konkretnej instancji, metoda klasy jest rodzajem konstruktora (dla wygody nic podobnego, MyClass(1,2,3)ale zamiast tego jak MyClass.get_special(1,2,3)), a metoda statyczna jest po prostu będąc normalną funkcją, która i tak mogłaby stać sama.
Zizouz212,
Tak, metody klasowe są zwykle używane dla alternatywnych konstruktorów (patrz mój przykład dict.fromkeys powyżej, patrz także kod źródłowy pandas.DataFrame), ale nie jest to cecha definiująca. Czasami potrzebuję jedynie dostępu do danych przechowywanych na poziomie klasy z metody, bez dostępu do instancji. Jeśli wywołujesz typ (self) (lub, co gorsza, self .__ class__) i nie używasz self bezpośrednio w metodzie instancji, to dobry znak, że powinieneś uznać to za metodę klasową. Ponieważ metody klas nie wymagają instancji, łatwiej jest je odrzucić.
Aaron Hall
4
  • „Metoda instancji” to metoda, która jako pierwszy parametr przekazuje obiekt instancji, który zgodnie z konwencją jest wywoływany self. To jest domyślne.

  • „Metoda statyczna” to metoda bez selfparametru początkowego . Jest to realizowane za pomocą dekoratora @staticmethod .

  • „Metoda klasy” to metoda, w której parametrem początkowym nie jest obiekt instancji, ale obiekt klasy ( zobacz w tej części dokumentacji Pythona, czym jest „obiekt klasy”), który zgodnie z konwencją jest nazywany cls. Jest to realizowane za pomocą dekoratora @classmethod .

Typowe użycie terminu „metoda statyczna” w C / C ++ / etc dotyczy zarówno metod „statycznych”, jak i „klasowych” Pythona, ponieważ w obu tych metodach nie ma odwołania do instancji. W C / C ++ / etc metody zwykle mają niejawny dostęp do wszystkich członków / metod klasy innych niż instancja, i prawdopodobnie dlatego to rozróżnienie istnieje tylko w językach takich jak Python / Ruby / etc.

Ixrec
źródło
Czy metoda statyczna w C / C ++ zawiera odwołanie do obiektu klasy? A może po prostu „członkowie” klasy? Czy mogą tworzyć nowych członków klasy? :)
Aaron Hall
3
@AaronHall W C / C ++ nie ma czegoś takiego jak obiekt klasy i nie potrzebujesz odwołania do niego, aby wywoływać metody statyczne. Po prostu piszesz Class::staticMethod()i to wszystko (o ile nie zabrania się dzwonić do niego, ponieważ staticMethod()jest prywatne lub coś w tym stylu).
Ixrec