Python'da statik yöntemler kullanmanın avantajı nedir?


91

Python'da kodla bağlantısız yöntem hatasıyla karşılaştım

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)

Buradaki birçok yararlı gönderiyi okuduktan sonra @staticmethod, kodu çalıştırmak için yukarıya nasıl ekleyebileceğimi anladım . Ben bir python acemisiyim. Lütfen birisi neden statik yöntemleri tanımlamak istediğini açıklayabilir mi? Veya neden tüm yöntemler statik yöntemler olarak tanımlanmıyor?


1
Bu tuhaf bir sorudur. Statik yöntemler bir tasarım gereğidir . Bu "avantaj" bir şey değil. Onları kullanmalısın çünkü mecbursun. Statik yöntemlere sahip olmak bir sınıfın tasarım özelliğidir. İlk etapta hangi statik yöntemlerin olduğunu mu soruyorsunuz? Bilmeniz gerekenleri daha net bir şekilde tanımlamak için sorunun yeniden ifade edilebileceğini düşünüyorum.
S.Lott

15
Hayır, ne olduklarını bilmek istemedim. Bilmek istediğim, başkalarının verdiği cevaplardan anlaşılan bunun neden bir "zorunluluk" olduğuydu. Bu, statik olmayan yöntemlerden ziyade onu ne zaman tanımlarsınız. Teşekkürler.
Curious2learn

3
@ S.Lott: Normal bir sınıf yöntemi kullanmak yerine statik yöntem kullanmak ne zaman bir gerekliliktir? Anladığım kadarıyla, bir sınıf yöntemi statik bir yöntemin yapabileceği her şeyi yapabilir. Staticmethod, bu yazıda başka yerlerde listelendiği gibi "avantajlara" sahip, ancak bir sınıf yönteminin statik bir yöntemin kullanılabileceği herhangi bir yerde kullanılamaması için herhangi bir neden göremiyorum, bu yüzden onu bir zorunluluk haline getiriyor.
RFV

Yanıtlar:


131

Statik yöntemlerin kullanımı sınırlıdır, çünkü bir sınıfın bir örneğinin özniteliklerine erişimleri yoktur (normal bir yöntemin yaptığı gibi) ve sınıfın kendi özniteliklerine erişimleri yoktur (bir sınıf yönteminin yaptığı gibi) ).

Bu yüzden günlük yöntemler için kullanışlı değiller.

Bununla birlikte, sağlanan parametreler dışında herhangi bir bilgiye (ve belki de modüle genel bazı özniteliklere) erişime ihtiyaç duymayan bir sınıfla birlikte (örneğin bir türden diğerine basit bir dönüşüm) bazı yardımcı program işlevlerini gruplamak yararlı olabilir. )

Sınıfın dışına konulabilirler, ancak onları sınıf içinde gruplamak, yalnızca orada uygulanabilecekleri yerlerde anlamlı olabilir.

Yönteme, modül adı yerine bir örnek veya sınıf aracılığıyla da başvurabilirsiniz; bu, okuyucunun yöntemin hangi örnekle ilişkili olduğunu anlamasına yardımcı olabilir.


9
@ Curious2learn: Her biri değil , ancak bazı yöntemler statik yöntemler olarak kullanışlıdır. LocaleÖrnekleri yerel (duh) olacak örnek bir sınıf düşünün . Bir getAvailableLocales()yöntem, böyle bir sınıfın statik yöntemine güzel bir örnek olabilir: açıkça Locale sınıfına aittir, ancak açıkça herhangi bir örneğe de ait değildir.
MestreLion

1
... ve sınıfların yöntemlerinden herhangi birine erişmesi gerekmeyebileceğinden, bir sınıf yöntemi de değildir.
MestreLion

1
Statik bir yöntem olduğuna dikkat bir editör noktaları olabilir açıkça aşağı giderek, sınıf niteliklere erişmek class_name.attribute, adil değil cls.attributeya self.attribute. Bu, "genel" öznitelikler için geçerlidir. Kural olarak, alt çizgiyle gizlenmiş özniteliklere veya iki alt çizgi ile karıştırılmış adlara bu şekilde erişmemelisiniz. Ayrıca, nitelikler miras hiyerarşisinde yer değiştirdiğinde kodunuzun daha kırılgan olacağı anlamına gelir.
Oddthinking

1
Statik yöntemlerin ne zaman kullanılacağına karar vermeye yardımcı olan Guido'dan bir alıntı (asla): "Hepimiz statik yöntemlerin ne kadar sınırlı olduğunu biliyoruz. (Bunlar temelde bir kazadır - yeni stil sınıfları ve tanımlayıcıları icat ettiğim Python 2.2 günlerinde , Sınıf yöntemlerini uygulamak istedim ama ilk başta onları anlamadım ve yanlışlıkla statik yöntemleri uyguladım. Sonra onları kaldırmak ve yalnızca sınıf yöntemleri sağlamak için çok geçti. "
Boris Churzin

192

Ayrıntılı açıklama için bu makaleye bakın .

TL; DR

1. selfArgüman kullanımını ortadan kaldırır .

2. Python'un başlatılan her nesne için bir bağlı yöntemi somutlaştırması gerekmediğinden bellek kullanımını azaltır :

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

3. Yöntemin nesnenin kendi durumuna bağlı olmadığını göstererek kod okunabilirliğini artırır.

4. Metod modül seviyesinde (yani sınıfın dışında) tanımlanmışsa, bir alt sınıf bu metodu geçersiz kılamayacağı için metodu geçersiz kılmaya izin verir.


3
Kabul edilen cevap bu olmalıdır. Herhangi bir örnekteki statik yöntemin ve sınıfın kendisinin aynı nesne olması, özellikle çok sayıda örneğiniz olduğunda (örneğin, değiştirilebilir bir veritabanı kaydı için her örnek) gerçek bir avantajdır.
Zhuoyun Wei

1
+1 ve @ZhuoyunWei ile aynı fikirde olun. Yalnızca statik bir yöntemin bazen bir sınıf yönteminden tercih edilebilir olmasının birkaç nedenini açıklayan yanıt (1 ve 3 gerçekten aynı neden olsa da).
Alex

2
"Neden statik yöntem" in en iyi yanıtı, ancak orijinal soru aynı zamanda "neden tüm yöntemler statik değil?" Kısa "örnek özniteliklerine erişim yok" bunu da kapsayacaktır.
exu

1
IMO'nun tek gerçek avantajı, onu bir alt sınıfta geçersiz kılabilmenizdir, ancak bu bile, OOP açısından yanlış bir şey yaptığınızı hissettiriyor, bunu hangi kullanım durumunda yapardınız?
Boris Churzin

1
3. - Devlet yoksa neden ilk etapta bir sınıf oluşturalım? modül işlevleri daha az kodla aynı derecede iyi olacaktır.
Alex

23

Bu tam olarak asıl sorunuzun noktasına gelmiyor, ancak bir python acemi olduğunuzu söylediğiniz için belki yardımcı olacaktır ve başka hiç kimse tam olarak çıkıp bunu açıkça söylemedi.

Yöntemi statik bir yöntem haline getirerek yukarıdaki kodu asla düzeltmezdim. Ya sınıfı terk eder ve sadece bir fonksiyon yazardım:

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

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

Çok sayıda ilişkili fonksiyonunuz varsa, bunları bir modülde gruplayabilirsiniz - yani hepsini aynı dosyaya koyun, sample.pyörneğin; sonra

import sample

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

Veya __init__sınıfa bir yöntem ekleyip yararlı yöntemlere sahip bir örnek oluşturabilirdim:

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)

(Ayrıca yukarıdaki örnekteki vaka kurallarını PEP 8 tarafından önerilen stile uyacak şekilde değiştirdim.)

Python'un avantajlarından biri, sizi her şey için sınıfları kullanmaya zorlamamasıdır. Bunları yalnızca yöntemlerle ilişkilendirilmesi gereken veri veya durum olduğunda kullanabilirsiniz, bu da sınıflar içindir. Aksi takdirde, işlevler için olan işlevleri kullanabilirsiniz.


Yorum için teşekkürler. Bu durumda bir sınıfa ihtiyacım vardı çünkü çizilen örnekle çalışmak istiyorum. Hayır, statik bir yöntem kullanmadım, ancak aldığım hata mesajıyla ilgili bilgilere bakarken terime rastladığım için öğrenmek istedim. Ancak, bir sınıfı tanımlamadan işlevleri bir modülde toplama konusundaki tavsiyeniz, ihtiyacım olan diğer işlevler için yardımcı olacaktır. Çok teşekkürler.
Curious2learn

4
+1: Bu, OP'nin sahip olduğu bazı yanlış kanıların güzel bir açıklamasıydı. Ve önceden, onun statik yöntemler hakkındaki sorusuna aslında cevap vermediğini söylemekte çok dürüsttün, bunun yerine probleminin ders gerektirmediğini söyleyerek çok daha iyi bir çözüm verdin .
MestreLion

22

Neden statik yöntemler tanımlamak istenir ?

Biz olduğunu varsayalım classdenilen Matho

kimse bir nesne oluşturmak isteyeceksiniz class Math
gibi yöntem ve ardından çağırmak ceilve floorve fabsüzerinde.

Bu yüzden onları yapıyoruz static.

Örneğin yapmak

>> Math.floor(3.14)

şundan çok daha iyi

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

Yani bir şekilde faydalıdırlar. Bunları kullanmak için bir sınıf örneği oluşturmanıza gerek yoktur.

Neden tüm yöntemler statik yöntemler olarak tanımlanmıyor ?

Örnek değişkenlerine erişimleri yoktur.

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

Bu yüzden tüm yöntemleri statik yapmıyoruz.


10
Ama neden bir paket matematik değil? Python'un bunun için paketleri vardır, bir ad alanı oluşturmak için bir sınıf tanımına ihtiyacınız yoktur .
extraneon

6
@ extraneon: Evet ahbap Bunu biliyorum ama basit ve tanıdık bir açıklama yapmak istedim ve kullandım Math. Bu yüzden büyük harf yazdım M.
Pratik Deoghare

6
OP, statik yöntemlerin ne olduğunu sormadı. Avantajlarının ne olduğunu sordu. Nasıl yararlı olduklarını değil, nasıl kullanacağınızı açıklıyorsunuz. Sizin özel örneğinizde, bir ad alanı çok daha mantıklı olacaktır.
Javier

4
-1: İyi ve doğru açıklama, ancak çok kötü seçilmiş bir örnek: Mathilk başta bir sınıf olmak için uydurma bir neden yok , bir modül daha uygun olur. "Kimsenin nesnesini yaratmak istemeyeceği" değil, sınıf olarak anlamlı olan bir sınıf örneği bulmaya çalışın .
MestreLion

3
Ve sonra , sınıfların yöntemlerinden biri (veya bazıları ) için, hepsinin olmasa da statik olması için yasal bir kullanım durumu örneği verin . Eğer bütün bir sınıfların yöntemleri statiktir, sınıf modülü olmalıdır. Eğer hiçbiri statiktir, o zaman soruya cevap verilmez.
MestreLion

15

Bir nesne örneğinden bir işlev nesnesi çağırdığınızda, bu bir 'bağlı yöntem' haline gelir ve örnek nesnenin kendisinin ilk argüman olarak iletilmesini sağlar.

Bir classmethodnesne örneğinde (bir işlev nesnesini saran) bir nesneyi çağırdığınızda , örnek nesnenin sınıfı ilk argüman olarak iletilir.

Bir staticmethodnesneyi çağırdığınızda (bir işlev nesnesini saran), örtük birinci argüman kullanılmaz.

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)

3
+1: Son olarak, statik yöntemlerin ve sınıf yöntemlerinin ne olduğuna dair harika bir açıklama . Neden statik bir yöntem kullanmak isteyebileceğinizi açıklamamış olsanız da , en azından basit bir örnekte, her ikisinin de resmi belgelerden çok daha iyi olduğunu açıkça açıkladınız .
MestreLion

5

Bir alternatifleri staticmethod: Hangi classmethod, instancemethodve function. Bunların ne olduğunu bilmiyorsanız, son bölüme ilerleyin. A staticmethodbu alternatiflerin herhangi birinden daha iyiyse, hangi amaçla yazıldığına bağlıdır.

Python statik yönteminin avantajları

  • Eğer nitelikleri veya sınıf veya örneğinin yöntemlerine erişimi gerekmiyorsa, bir staticmethodbir daha iyidir classmethodya instancemethod. Bu şekilde @staticmethod, sınıfın ve örneğin durumunun okunmadığı veya değiştirilmediği ( dekoratörden) açıktır . Ancak, a kullanmak functionbu ayrımı daha da netleştirir (dezavantajlara bakınız).
  • A'nın çağrı imzası staticmethoda classmethodveya ile aynıdır instancemethod, yani <instance>.<method>(<arguments>). Bu nedenle , daha sonra veya türetilmiş bir sınıfta gerekirse üçünden biri ile kolayca değiştirilebilir . Bunu basit bir ile yapamazsınız function.
  • Öznel olarak bir sınıfa ait olduğunu açıklığa kavuşturmak ve ad alanı çakışmalarını önlemek için a staticmethodyerine A kullanılabilir function.

Python statik yönteminin dezavantajları

  • Örnek veya sınıfın özniteliklerine veya yöntemlerine erişemez.
  • A'nın çağrı imzası staticmethod, a classmethodveya ile aynıdır instancemethod. Bu, gerçekte staticmethodherhangi bir nesne bilgisini okumadığı veya değiştirmediği gerçeğini maskeler . Bu, kodun okunmasını zorlaştırır. Neden sadece a kullanmıyorsunuz function?
  • A'yı staticmethod, tanımlandığı sınıf / örnek dışından çağırmanız gerekirse yeniden kullanmak zordur. Yeniden kullanım potansiyeli varsa, a functiondaha iyi seçimdir.
  • staticmethodİnsanlar bir Okumak için biraz daha uzun sürebilir içeren kod okuma böylece nadiren kullanılır.

Python'da statik bir yönteme alternatifler

Avantajlarını tartışmak için staticmethod, alternatiflerin ne olduğunu ve birbirlerinden nasıl farklı olduklarını bilmemiz gerekir.

  • staticmethodSmıfındandır ancak erişmek veya herhangi bir örnek veya sınıf bilgilerini değiştiremez.

Bunun üç alternatifi var:

  • classmethodArayanın sınıfına erişimi vardır.
  • instancemethodArayanın Örneğin ve kendi sınıfında erişimi vardır.
  • functionSınıflar ile ilgisi vardır. En yakın yetenek staticmethod.

İşte bunun kodda nasıl göründüğü:

# 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

3

Statik yöntemler harikadır çünkü yöntemin ait olduğu nesnenin bir örneğini bildirmeniz gerekmez.

python sitesinde statik yöntemlerle ilgili harika belgeler var:
http://docs.python.org/library/functions.html#staticmethod


Teşekkürler David. Ama o zaman neden her yöntemi statik bir yöntem olarak tanımlamıyorsunuz, çünkü bunlar örnekler üzerinde de çalışıyorlar. Bunu yapmanın herhangi bir sakıncası var mı?
Curious2learn

4
@ Curious2learn: Hayır, statik yöntemlerle örneğe erişiminiz yok: Örnek, sınıfı dışında yok sayılır.
Felix Kling

4
Bu argüman, işlevlerin kendi başına yaşayamayacağı, ancak her zaman bir sınıf bağlamında tanımlandığı Java'da doğru olacaktır. Ancak Python'da işlevlere ve statik sınıf işlevlerine sahip olabilirsiniz. Bu cevap, sınıfta olmayan bir yöntem yerine neden statik bir yöntem seçileceğini gerçekten göstermez.
extraneon

1
@ extraneon - bu daha çok organizasyonel kod tercihleri ​​meselesidir; statik yöntemlere sahip olmak, birine ekstra seçenek verir.
Charles Duffy

@Felix - Teşekkürler. Bu, her yöntemin neden statik bir yöntem olmaması gerektiğini açıklar.
Curious2learn

1

Statik yöntemlerin Python'da olması için neredeyse hiçbir nedeni yoktur. Örnek yöntemlerini veya sınıf yöntemlerini kullanırsınız.

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

"Neredeyse" dedin. Alternatiflerden daha iyi olabilecekleri bir yer var mı?
Javier

@Javier: Bir tane düşünemiyorum ama muhtemelen bir tane var, aksi halde neden bu yöntem Python kitaplığına dahil edilsin?
Georg Schölly

1
@Javier, @Georg: Python külliyatında zaaf olmadığına inancınız büyük.
Charles Merriam

-1: Bu cevap, a'nın ne olduğu veya neden olduğu ve statik olanlardan nasıl "daha iyi" olduğu konusunda herhangi bir kullanım durumu staticmethodveya herhangi bir açıklama classmethodsunmamaktadır.
MestreLion

@CharlesMerriam: Elbette statik yöntemlerin kullanımları vardır, aksi takdirde Python 3'te (eski bozukluğun çoğunun kaldırıldığı) bırakılır veya kullanımdan kaldırılırdı. Bir yoktur tek karşı sözcük staticmethoddokümanlar, cruft veya Georg'un iddiası olduğunu iddianızı destekleyen de classmethodyerine kullanılmalıdır).
MestreLion

1

Ad alanı işlevleri güzel olduğundan (daha önce belirtildiği gibi):

  1. Nesnenin durumunu değiştirmeyen yöntemler hakkında açık olmak istediğimde, statik yöntemler kullanıyorum. Bu, ekibimdeki kişilerin bu yöntemlerde nesnenin niteliklerini değiştirmeye başlamasını teşvik ediyor.

  2. Gerçekten çürümüş kodu yeniden düzenlediğimde, @staticmethodmümkün olduğunca çok yöntem yapmaya çalışarak başlıyorum . Bu, daha sonra bu yöntemleri bir sınıfa çıkarmama izin veriyor - kabul etsem de, bu nadiren kullandığım bir şey, birkaç kez faydalı oldu.


1

Tahminime göre, işlevi sınıfın dışında ve sınıftan ayrı olarak tanımlamaya kıyasla s kullanmanın tek bir performans faydası yok @staticmethod, aksi takdirde bir@staticmethod .

Varlıklarını haklı çıkaran tek şey rahatlıktır. Statik yöntemler diğer popüler programlama dillerinde yaygındır, öyleyse neden python olmasın? Onu oluşturduğunuz sınıfla çok yakından ilişkili bir davranışa sahip bir işlev oluşturmak istiyorsanız, ancak aslında sınıfın bir örneğinin iç verilerine, onu tipik bir Bu sınıfın yöntemi daha sonra @staticmethodüstüne bir tokat atar ve kodunuzu okuyan herkes, yöntemin doğası ve sınıfla ilişkisi hakkında hemen çok şey öğrenecektir.

Ara sıra yapmaktan hoşlandığım bir şey, sınıfımın dahili olarak çokça kullandığı işlevselliği özel @staticmethode-postalara yerleştirmektir. Bu şekilde, modülüm tarafından açığa çıkan API'yi, modülümü kullanan hiç kimsenin kullanmak şöyle dursun görmeye ihtiyaç duymayacağı yöntemlerle karıştırmam.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.