Jakie są zalety używania metod statycznych w Pythonie?

90

Napotkałem niezwiązany błąd metody w Pythonie z kodem

import random

class Sample(object):
'''This class defines various methods related to the sample'''

    def drawSample(samplesize,List):
        sample=random.sample(List,samplesize)
        return sample

Choices=range(100)
print Sample.drawSample(5,Choices)

Po przeczytaniu wielu pomocnych postów pomyślałem, jak mogę dodać @staticmethodpowyżej, aby kod działał. Jestem nowicjuszem w Pythonie. Czy ktoś mógłby wyjaśnić, dlaczego chciałoby się zdefiniować metody statyczne? Albo dlaczego nie wszystkie metody są zdefiniowane jako metody statyczne?

Curious2learn
źródło
1
To dziwne pytanie. Metody statyczne są koniecznością projektową . To nie jest kwestia „przewagi”. Używasz ich, bo musisz. Jest to cecha projektowa klasy, która ma metody statyczne. Pytasz, jakie metody statyczne są w pierwszej kolejności? Myślę, że pytanie można przeformułować, aby jaśniej zdefiniować to, co musisz wiedzieć.
S.Lott
15
Nie, nie chciałem wiedzieć, czym one są. Chciałem wiedzieć, dlaczego jest to „konieczność”, co stało się jasne na podstawie odpowiedzi udzielonych przez innych. Właśnie wtedy zdefiniowałbyś to zamiast metod niestatycznych. Dzięki.
Curious2learn
3
@ S.Lott: Kiedy użycie metody statycznej jest konieczne, w przeciwieństwie do zwykłej metody klasowej? O ile wiem, metoda klasowa może zrobić wszystko, co może metoda statyczna. Metoda statyczna ma "zalety" wymienione w innym miejscu w tym poście, ale nie widzę żadnych powodów, dla których metoda klasowa nie może być używana w żadnym miejscu, w którym można by użyć metody statycznej, co czyni ją koniecznością.
RFV

Odpowiedzi:

128

Metody statyczne mają ograniczone zastosowanie, ponieważ nie mają dostępu do atrybutów instancji klasy (jak ma to zwykła metoda) i nie mają dostępu do atrybutów samej klasy (tak jak metoda klasowa ).

Nie są więc przydatne w codziennych metodach.

Mogą być jednak przydatne do zgrupowania jakiejś funkcji narzędzia razem z klasą - np. Prosta konwersja z jednego typu na inny - która nie potrzebuje dostępu do żadnych informacji poza podanymi parametrami (i być może niektórych atrybutów globalnych dla modułu. )

Można je umieścić poza klasą, ale zgrupowanie ich wewnątrz klasy może mieć sens tam, gdzie mają zastosowanie tylko tam.

Możesz również odwoływać się do metody za pośrednictwem instancji lub klasy, a nie nazwy modułu, co może pomóc czytelnikowi zrozumieć, z jakim wystąpieniem metoda jest powiązana.

Dziwne
źródło
8
@ Curious2learn: Nie każdy , ale niektóre metody są przydatne jako metody statyczne. Pomyśl o przykładowej Localeklasie, której instancje będą lokalnymi (duh). getAvailableLocales()Metodą byłoby dobrym przykładem metody statycznej takiej klasy: to wyraźnie należą do klasy Locale, a także wyraźnie nie należą do żadnej konkretnej instancji.
MestreLion
... i nie jest to również metoda klasowa, ponieważ może nie potrzebować dostępu do żadnej z metod klas.
MestreLion
Edytor wskazuje, że metoda statyczna może uzyskać dostęp do atrybutów klasy, jawnie przechodząc w dół od class_name.attribute, po prostu nie cls.attributelub self.attribute. Dotyczy to atrybutów „publicznych”. Zgodnie z konwencją, w ten sposób nie należy uzyskiwać dostępu do atrybutów ukrytych za pomocą podkreślenia lub nazw zniekształconych dwoma podkreśleniami. Oznacza to również, że twój kod będzie bardziej kruchy, gdy atrybuty przesuną się o miejsca w hierarchii dziedziczenia.
Oddthinking
Cytat z Guido, który pomaga zdecydować, kiedy użyć metod statycznych (nigdy): „Wszyscy wiemy, jak ograniczone są metody statyczne. (W zasadzie są one przypadkiem - w Pythonie 2.2 dni, kiedy wymyślałem klasy i deskryptory w nowym stylu , Chciałem zaimplementować metody klasowe, ale na początku ich nie rozumiałem i przypadkowo zaimplementowałem najpierw metody statyczne. Potem było już za późno na ich usunięcie i udostępnianie tylko metod klasowych. ”
Boris Churzin
189

Zobacz ten artykuł, aby uzyskać szczegółowe wyjaśnienie.

TL; DR

1. eliminuje użycie selfargumentu.

Zmniejsza to zużycie pamięci, ponieważ Python nie musi tworzyć instancji metody powiązanej dla każdego instancjonowanego obiektu:

>>>RandomClass().regular_method is RandomClass().regular_method
False
>>>RandomClass().static_method is RandomClass().static_method
True
>>>RandomClass.static_method is RandomClass().static_method
True

Poprawia czytelność kodu, co oznacza, że ​​metoda nie zależy od stanu samego obiektu.

4. Pozwala na nadpisywanie metody w tym sensie, że gdyby metoda została zdefiniowana na poziomie modułu (tj. Poza klasą), podklasa nie byłaby w stanie przesłonić tej metody.

zanetu
źródło
3
To powinna być akceptowana odpowiedź. Fakt, że metoda statyczna w dowolnych instancjach i sama klasa są tym samym obiektem, jest prawdziwą zaletą, zwłaszcza gdy masz wiele instancji (np. Każda instancja dla mutowalnego rekordu bazy danych).
Zhuoyun Wei
+1 i zgadzam się z @ZhuoyunWei. Jedyna odpowiedź, która wyjaśnia kilka powodów, dla których metoda statyczna jest czasami lepsza niż metoda klasowa (chociaż 1 i 3 to w rzeczywistości ten sam powód).
Alex
1
Najlepsza odpowiedź na pytanie „dlaczego metoda statyczna”, ale oryginalne pytanie dotyczyło również „dlaczego wszystkie metody nie są statyczne?”. Krótkie „brak dostępu do atrybutów instancji” też by to obejmowało.
Exu
IMO jedyną prawdziwą zaletą jest to, że możesz zastąpić to w podklasie, ale nawet to ma poczucie, że robisz coś źle z punktu widzenia OOP, w jakim przypadku byś to zrobił?
Boris Churzin
23

To nie jest do końca sedno twojego rzeczywistego pytania, ale skoro powiedziałeś, że jesteś nowicjuszem w Pythonie, być może będzie to pomocne, a nikt inny nie wyszedł i nie powiedział tego wyraźnie.

Nigdy nie naprawiłbym powyższego kodu, czyniąc metodę metodą statyczną. Albo porzuciłbym klasę i po prostu napisałbym funkcję:

def drawSample(samplesize,List):
    sample=random.sample(List,samplesize)
    return sample

Choices=range(100)
print drawSample(5,Choices)

Jeśli masz wiele powiązanych funkcji, możesz je zgrupować w module - tj. Umieścić je wszystkie w tym samym pliku, nazwanym sample.pyna przykład; następnie

import sample

Choices=range(100)
print sample.drawSample(5,Choices)

Albo dodałbym __init__metodę do klasy i utworzyłbym instancję, która zawierałaby przydatne metody:

class Sample(object):
'''This class defines various methods related to the sample'''

    def __init__(self, thelist):
        self.list = thelist

    def draw_sample(self, samplesize):
        sample=random.sample(self.list,samplesize)
        return sample

choices=Sample(range(100))
print choices.draw_sample(5)

(Zmieniłem również konwencje przypadku w powyższym przykładzie, aby pasowały do ​​stylu zalecanego przez PEP 8.)

Jedną z zalet Pythona jest to, że nie wymusza używania klas do wszystkiego. Możesz ich używać tylko wtedy, gdy istnieją dane lub stan, które powinny być skojarzone z metodami, do czego służą klasy. W przeciwnym razie możesz używać funkcji, do czego służą funkcje.

Vicki Laidler
źródło
Dziękuję za komentarz. W tym przypadku potrzebowałem zajęć, ponieważ chcę pracować z narysowaną próbką. Nie, nie korzystałem z metody statycznej, ale chciałem się dowiedzieć, ponieważ natrafiłem na ten termin, szukając informacji o komunikacie o błędzie, który otrzymałem. Twoja rada dotycząca gromadzenia funkcji w module bez definiowania klasy byłaby pomocna w przypadku innych potrzebnych mi funkcji. Więc dziękuję.
Curious2learn
4
+1: To było miłe wyjaśnienie niektórych nieporozumień PO. I byłeś bardzo szczery, mówiąc z góry, że tak naprawdę nie odpowiadałeś na jego pytanie o metody statyczne, ale raczej podałeś znacznie lepsze rozwiązanie, mówiąc, że jego problem w ogóle nie wymaga zajęć.
MestreLion
22

Dlaczego chciałoby się definiować metody statyczne ?

Załóżmy, że mamy wtedy classwezwanieMath

nikt nie będzie chciał tworzyć obiektu, class Math
a następnie wywoływać metody takie jak ceili floori fabsna nim.

Więc je robimy static.

Na przykład robienie

>> Math.floor(3.14)

jest znacznie lepszy niż

>> mymath = Math()
>> mymath.floor(3.14)

Więc są w jakiś sposób przydatne. Nie musisz tworzyć instancji klasy, aby ich używać.

Dlaczego nie wszystkie metody są zdefiniowane jako metody statyczne ?

Nie mają dostępu do zmiennych instancji.

class Foo(object):
    def __init__(self):
        self.bar = 'bar'

    def too(self):
        print self.bar

    @staticmethod
    def foo():
        print self.bar

Foo().too() # works
Foo.foo() # doesn't work

Dlatego nie wszystkie metody są statyczne.

Pratik Deoghare
źródło
10
Ale dlaczego nie matematyka pakietu? Python ma do tego pakiety, nie potrzebujesz definicji klasy, aby utworzyć przestrzeń nazw.
extraneon
6
@extraneon: Tak stary, wiem to, ale chciałem mieć coś prostego i znajomego do wyjaśnienia, więc użyłem Math. Dlatego skapitalizowałem M.
Pratik Deoghare
6
OP nie zapytał, jakie są metody statyczne. Zapytał, jaka jest ich przewaga. Tłumaczysz, jak ich używać, a nie jak są przydatne. W twoim konkretnym przykładzie przestrzeń nazw miałaby znacznie większy sens.
Javier
4
-1: Dobre i poprawne wyjaśnienie, ale bardzo źle wybrany przykład: nie ma powodu, dla którego stworzyłeś Mathklasę w pierwszej kolejności, moduł byłby lepiej dopasowany. Spróbuj znaleźć przykład klasy, która miałaby sens jako klasa, a nie takiej, z której „nikt nie będzie chciał stworzyć obiektu” .
MestreLion
3
A następnie podaj przykład legalnego przypadku użycia dla jednej (lub kilku ) metod klas, które mają być statyczne, ale nie wszystkie . Jeśli wszystkie metody klas są statyczne, klasa powinna być modułem. Jeśli żaden nie jest statyczny, nie odpowiadasz na pytanie.
MestreLion
13

Kiedy wywołujesz obiekt funkcji z instancji obiektu, staje się on „metodą powiązaną” i pobiera sam obiekt instancji jako pierwszy argument.

Kiedy wywołujesz classmethodobiekt (który opakowuje obiekt funkcji) w instancji obiektu, klasa obiektu instancji jest przekazywana jako pierwszy argument.

Kiedy wywołujesz staticmethodobiekt (który otacza obiekt funkcji), nie jest używany żaden niejawny pierwszy argument.

class Foo(object):

    def bar(*args):
        print args

    @classmethod
    def baaz(*args):
        print args

    @staticmethod
    def quux(*args):
        print args

>>> foo = Foo()

>>> Foo.bar(1,2,3)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unbound method bar() must be called with Foo instance as first argument (got int instance instead)
>>> Foo.baaz(1,2,3)
(<class 'Foo'>, 1, 2, 3)
>>> Foo.quux(1,2,3)
(1, 2, 3)

>>> foo.bar(1,2,3)
(<Foo object at 0x1004a4510>, 1, 2, 3)
>>> foo.baaz(1,2,3)
(<class 'Foo'>, 1, 2, 3)
>>> foo.quux(1,2,3)
(1, 2, 3)
Matt Anderson
źródło
3
+1: Wreszcie świetne wyjaśnienie, czym są metody statyczne i metody klas. Chociaż nie wyjaśniłeś, dlaczego ktoś miałby chcieć użyć metody statycznej, przynajmniej jasno wyjaśniłeś na prostym przykładzie, co obie znacznie lepsze niż oficjalna dokumentacja.
MestreLion
3

metody statyczne są świetne, ponieważ nie musisz deklarować wystąpienia obiektu, do którego należy metoda.

Witryna pythona zawiera świetną dokumentację dotyczącą metod statycznych:
http://docs.python.org/library/functions.html#staticmethod

David Fox
źródło
Dzięki David. Ale dlaczego nie zdefiniować każdej metody jako metody statycznej, ponieważ działają one również na instancjach. Czy są jakieś wady takiego postępowania?
Curious2learn
4
@ Curious2learn: Nie, przy metodach statycznych nie masz dostępu do instancji: instancja jest ignorowana z wyjątkiem jej klasy.
Felix Kling
4
Ten argument byłby prawdziwy w Javie, gdzie funkcje nie mogą funkcjonować samodzielnie, ale są zawsze definiowane w kontekście klasy. Ale w Pythonie możesz mieć funkcje i statyczne funkcje klas. Ta odpowiedź tak naprawdę nie pokazuje, dlaczego wybrać metodę statyczną zamiast metody spoza klasy.
extraneon
1
@extraneon - to bardziej kwestia preferencji organizacyjnych kodu; posiadanie metod statycznych daje dodatkową opcję.
Charles Duffy
@Felix - Dzięki. To wyjaśnia, dlaczego każda metoda nie powinna być metodą statyczną.
Curious2learn
3

Alternatywy do A staticmethodto: classmethod, instancemethod, i function. Jeśli nie wiesz, co to jest, przewiń w dół do ostatniej sekcji. Jeśli a staticmethodjest lepsze niż którakolwiek z tych alternatyw, zależy to od tego, w jakim celu jest napisane.

zalety statycznej metody Pythona

  • Jeśli nie potrzebujesz dostępu do atrybutów lub metod klasy lub instancji, a staticmethodjest lepsze niż classmethodlub instancemethod. W ten sposób jest jasne (od @staticmethoddekoratora), że stan klasy i instancji nie jest odczytywany ani modyfikowany. Jednak użycie znaku functionsprawia, że ​​to rozróżnienie jest jeszcze jaśniejsze (patrz wady).
  • Podpis wywołania a staticmethodjest taki sam jak a classmethodlub instancemethod, a mianowicie <instance>.<method>(<arguments>). Dlatego można go łatwo zastąpić jednym z trzech, jeśli będzie to potrzebne później lub w klasie pochodnej. Nie możesz tego zrobić za pomocą prostego function.
  • staticmethodMoże być stosowany zamiast functionwyjaśnić, że to subiektywnie należy do klasy i aby uniknąć konfliktów nazw.

wady statycznej metody Pythona

  • Nie może uzyskać dostępu do atrybutów ani metod instancji lub klasy.
  • Podpis połączenia a staticmethodjest taki sam, jak podpis a classmethodlub instancemethod. To maskuje fakt, że w staticmethodrzeczywistości nie czyta ani nie modyfikuje żadnych informacji o obiekcie. To sprawia, że ​​kod jest trudniejszy do odczytania. Dlaczego po prostu nie użyć function?
  • A staticmethodjest trudne do ponownego użycia, jeśli kiedykolwiek będziesz musiał wywołać go spoza klasy / instancji, w której został zdefiniowany. Jeśli istnieje jakikolwiek potencjał do ponownego wykorzystania, functionlepszym wyborem jest a.
  • staticmethodJest rzadko używany, więc ludzie czytając kod, który zawiera jeden może trwać nieco dłużej, aby ją przeczytać.

alternatywy dla metody statycznej w Pythonie

Aby omówić zalety programu staticmethod, musimy wiedzieć, jakie są alternatywy i czym się od siebie różnią.

  • staticmethodNależy do klasy, ale nie ma dostępu ani modyfikować żadnych instancji lub klasy informacje.

Istnieją trzy alternatywy:

  • classmethodMa dostęp do klasy rozmówcy.
  • instancemethodMa dostęp do instancji rozmówcy i jego klasę.
  • Nie functionma to nic wspólnego z zajęciami. Jest najbliżej możliwości do staticmethod.

Oto jak to wygląda w kodzie:

# function
# has nothing to do with a class
def make_cat_noise(asker_name):
    print('Hi %s, mieets mieets!' % asker_name)

# Yey, we can make cat noises before we've even defined what a cat is!
make_cat_noise('JOey')  # just a function

class Cat:
    number_of_legs = 4

    # special instance method __init__
    def __init__(self, name):
        self.name = name

    # instancemethod
    # the instance (e.g. Cat('Kitty')) is passed as the first method argument
    def tell_me_about_this_animal(self, asker_name):
        print('Hi %s, This cat has %d legs and is called %s'
              % (asker_name, self.number_of_legs, self.name))

    # classmethod
    # the class (e.g. Cat) is passed as the first method argument
    # by convention we call that argument cls
    @classmethod
    def tell_me_about_cats(cls, asker_name):
        print("Hi %s, cats have %d legs."
              % (asker_name, cls.number_of_legs))
        # cls.name  # AttributeError because only the instance has .name
        # self.name  # NameError because self isn't defined in this namespace

    # staticmethod
    # no information about the class or the instance is passed to the method
    @staticmethod
    def make_noise(asker_name):
        print('Hi %s, meooow!' % asker_name)
        # class and instance are not accessible from here

# one more time for fun!
make_cat_noise('JOey')  # just a function

# We just need the class to call a classmethod or staticmethod:
Cat.make_noise('JOey')  # staticmethod
Cat.tell_me_about_cats('JOey')  # classmethod
# Cat.tell_me_about_this_animal('JOey')  # instancemethod -> TypeError

# With an instance we can use instancemethod, classmethod or staticmethod
mycat = Cat('Kitty')  # mycat is an instance of the class Cat
mycat.make_noise('JOey')  # staticmethod
mycat.tell_me_about_cats('JOey')  # classmethod
mycat.tell_me_about_this_animal('JOey')  # instancemethod
Joooeey
źródło
1

Ponieważ funkcje z przestrzenią nazw są fajne (jak wcześniej wskazano):

  1. Kiedy chcę jasno określić metody, które nie zmieniają stanu obiektu, używam metod statycznych. To zniechęca ludzi w moim zespole do zmiany atrybutów obiektu w tych metodach.

  2. Kiedy naprawiam naprawdę zgniły kod, zaczynam od stworzenia jak największej liczby metod @staticmethod. To pozwala mi następnie wyodrębnić te metody do klasy - chociaż zgadzam się, rzadko jest to coś, czego używam, przydało mi się kilka razy.

vlad-ardelean
źródło
1

W mojej ocenie, nie ma jednego wydajność zaletą korzystania @staticmethods porównaniu do zaledwie definiowania poza funkcją i oddzielone od klasy byłoby inaczej @staticmethodod.

Jedyne, co powiedziałbym, że uzasadnia ich istnienie, to wygoda. Metody statyczne są powszechne w innych popularnych językach programowania, więc dlaczego nie python? Jeśli chcesz utworzyć funkcję z zachowaniem, które jest bardzo ściśle powiązane z klasą, dla której ją tworzysz, ale w rzeczywistości nie uzyskuje ona dostępu / modyfikuje wewnętrznych danych instancji klasy w sposób, który uzasadnia konceptualizację jej jako typowej metoda tej klasy, a następnie uderz @staticmethodją powyżej, a każdy, kto czyta Twój kod, natychmiast nauczy się dużo o naturze metody i jej związku z klasą.

Jedną z rzeczy, które czasami lubię robić, jest umieszczanie funkcji, z których moja klasa korzysta wewnętrznie, w prywatnych @staticmethodusługach. W ten sposób nie zaśmiecam interfejsu API udostępnianego przez mój moduł metodami, których nikt używający mojego modułu nigdy nie musiałby widzieć, nie mówiąc już o użyciu.

Garrett Gutierrez
źródło
0

Metody statyczne nie mają prawie żadnego powodu, by być w Pythonie. Używasz metod instancji lub metod klas.

def method(self, args):
    self.member = something

@classmethod
def method(cls, args):
    cls.member = something

@staticmethod
def method(args):
    MyClass.member = something
    # The above isn't really working
    # if you have a subclass
Georg Schölly
źródło
Powiedziałeś „prawie”. Czy jest miejsce, w którym mogą być lepsze niż alternatywy?
Javier
@Javier: Nie przychodzi mi do głowy żaden, ale prawdopodobnie taki istnieje, dlaczego w przeciwnym razie ta metoda miałaby być włączona do biblioteki Pythona?
Georg Schölly
1
@Javier, @Georg: Masz wielką wiarę, że korpus Pythona nie ma skorupy.
Charles Merriam
-1: Ta odpowiedź nie przedstawia żadnego przypadku użycia staticmethodani żadnego wyjaśnienia, czym classmethodjest a, dlaczego i jak jest „lepsze” niż statyczne.
MestreLion
@CharlesMerriam: Oczywiście metody statyczne mają swoje zastosowanie, w przeciwnym razie zostałby porzucony lub przestarzały w Pythonie 3 (gdzie większość starego cruft został usunięty). W dokumentach nie ma ani jednego słowa przeciwko, staticmethodktóre potwierdziłoby twoje twierdzenie, że jest to okrucieństwo lub twierdzenie Georga, które classmethodpowinno być użyte zamiast tego).
MestreLion