Soru Python'da @staticmethod ve @classmethod arasındaki fark nedir?


İle süslü bir işlev arasındaki fark nedir @staticmethod ve bir ile dekore @classmethod?


2675
2017-09-25 21:01


Menşei


Statik yöntemler, temizlik amacıyla pythonda modül seviyesi işlevleri olarak bazen daha iyidir. Bir modül fonksiyonu ile ihtiyacınız olan fonksiyonu almak ve gereksiz "" önlemek için daha kolaydır. " sözdizimi (Sana bakıyorum Objective-C). Sınıf yöntemleri, "fabrika düzeni" fonksiyonlarını oluşturmak için polimorfizm ile birlikte kullanıldıklarından daha fazla kullanıma sahiptir. Bunun nedeni sınıf yöntemlerinin sınıfı örtülü bir parametre olarak almasıdır. - FistOfFury
tl; dr >> normal yöntemlerle kıyaslandığında, statik yöntemler ve sınıf yöntemlerine de sınıf kullanılarak erişilebilir ancak sınıf yöntemlerinden farklı olarak, statik yöntemler kalıtım yoluyla değişmezdir. - imsrgadich


Cevaplar:


Belki biraz örnek kod size yardımcı olacaktır: foo, class_foo ve static_foo:

class A(object):
    def foo(self,x):
        print "executing foo(%s,%s)"%(self,x)

    @classmethod
    def class_foo(cls,x):
        print "executing class_foo(%s,%s)"%(cls,x)

    @staticmethod
    def static_foo(x):
        print "executing static_foo(%s)"%x    

a=A()

Aşağıda, bir nesne örneğinin bir yöntemi çağırdığı normal yoldur. Nesne örneği a, ilk argüman olarak örtük olarak geçmiştir.

a.foo(1)
# executing foo(<__main__.A object at 0xb7dbef0c>,1)

Sınıf yöntemleri ile, nesne örneğinin sınıfı, yerine, ilk argüman olarak örtülü olarak iletilir. self.

a.class_foo(1)
# executing class_foo(<class '__main__.A'>,1)

Ayrıca arayabilirsiniz class_foo sınıfını kullanıyor. Aslında, bir şey tanımlarsanız Bir classmethod, muhtemelen bir sınıf örneğinden ziyade sınıftan onu aramak niyetindesinizdir. A.foo(1) bir TypeError ortaya çıkardı, ama A.class_foo(1) iyi çalışıyor:

A.class_foo(1)
# executing class_foo(<class '__main__.A'>,1)

Sınıf metotları için bir kişinin bulduğu bir yöntem yaratmaktır. kalıtsal alternatif kurucular.


Staticmethods ilene ikisi de self (nesne örneği) ve cls (sınıf) örtülü olarak ilk argüman olarak geçmiştir. Bunları bir örnek veya sınıftan arayabilmeniz dışında düz işlevler gibi davranırlar:

a.static_foo(1)
# executing static_foo(1)

A.static_foo('hi')
# executing static_foo(hi)

Statik ölçümler, bir sınıfla sınıfa mantıksal bağları olan işlevleri gruplandırmak için kullanılır.


foo sadece bir işlev ama aradığınızda a.foo sadece işlevi almazsın Nesne örneğiyle işlevin "kısmen uygulanmış" bir sürümünü alırsınız a işlevin ilk argümanı olarak bağlanır. foo 2 argüman beklerken a.foo sadece 1 argüman bekler.

a bağlı foo. Aşağıdaki "bağlı" terimi ile kastedilen şey:

print(a.foo)
# <bound method A.foo of <__main__.A object at 0xb7d52f0c>>

İle a.class_foo, a bağlı değil class_foodaha ziyade sınıf A bağlı class_foo.

print(a.class_foo)
# <bound method type.class_foo of <class '__main__.A'>>

Burada, bir statik yöntemle, bir yöntem olsa bile, a.static_foo sadece döner hiçbir argüman olmadan iyi bir ole işlevi. static_foo 1 argüman bekliyor ve a.static_foo 1 argümanı da bekliyor.

print(a.static_foo)
# <function static_foo at 0xb7d479cc>

Ve tabii ki aynı şey aradığınızda da olur static_foo sınıfla A yerine.

print(A.static_foo)
# <function static_foo at 0xb7d479cc>

2320
2017-11-03 19:13



Statik yöntem kullanmanın ne anlama geldiğini anlamıyorum. Sadece sınıf dışı basit bir işlev kullanabiliriz. - Alcott
@Alcott: Bir işlevi bir sınıfa taşımak isteyebilirsiniz çünkü mantıksal olarak sınıfa aittir. Python kaynak kodunda (örneğin çoklu işlem, kaplumbağa, dağıtım paketleri), modül ad alanından tek altçaplı "özel" işlevleri "gizlemek" için kullanılır. Bununla birlikte, kullanımı sadece birkaç modülde yoğunlaşmıştır - belki de bunun esas olarak stilistik bir şey olduğunun bir göstergesidir. Bununla ilgili bir örnek bulamadım. @staticmethod alt sınıflar tarafından geçersiz kılınarak kodunuzu düzenlemenize yardımcı olabilir. Bu olmadan, modül ad alanında dolaşan işlevlerin varyantları olur. - unutbu
... bazı açıklamalarla birlikte nerede ve niye ya örnek, sınıf veya statik yöntemleri kullanmak. Bununla ilgili tek bir kelime vermediniz, ama OP de bunu sormadı. - MestreLion
@Alcott: unutbu'nun söylediği gibi, statik yöntemler bir organizasyon / stilistik özelliktir. Bazen bir modülün birçok sınıfı vardır ve bazı yardımcı fonksiyonlar mantıksal olarak belirli bir sınıfa ve diğerlerine bağlı değildir, bu yüzden modülü "serbest fonksiyonlar" ile "kirletmemek" ve statik kullanmak daha mantıklıdır. yöntem, karıştırma sınıflarının zayıf biçimine ve kodla birlikte işlev bozukluklarının "ilişkili" olduklarını göstermek için - MestreLion
@unutbu: Ancak şu Guido teklifini silmelisiniz: python 2.2 sürüm notlarının erken bir taslağından gelmişti ve 2.2.3'te şöyle değiştirildi: However, class methods are still useful in other places, for example, to program inheritable alternate constructors.Orijinal alıntı bile çok yanıltıcıdır, çünkü sadece python dağıtımı kullanmaz classmethod. Fakat pythonun kendisinin belirli bir özelliği kullanmadığı için, bunun faydasız bir özellik olduğu anlamına gelmez. Hakkında düşün Karışık sayılar ya da sqrt: Python'un kendisi de kullanamaz, ama işe yaramaz olmaktan çok uzaktır. - MestreLion


bir durukyöntem çağrıldığı sınıf veya örnek hakkında hiçbir şey bilmeyen bir yöntemdir. Sadece geçen argümanlar, örtük ilk argümanları alır. Python'da temelde işe yaramaz - sadece staticmethod yerine bir modül fonksiyonu kullanabilirsiniz.

bir classmethodÖte yandan, çağrıldığı sınıfı ya da çağrıldığı vakanın sınıfını ilk argüman olarak alan bir yöntemdir. Bu yöntem, yöntemin sınıf için bir fabrika olmasını istediğinizde yararlıdır: ilk argüman olarak adlandırılan gerçek sınıfı aldığından, alt sınıflar dahil olsa bile daima doğru sınıfı başlatabilirsiniz. Örneğin nasıl gözlemleyin dict.fromkeys(), bir classmethod, alt sınıfta çağrıldığında alt sınıfın bir örneğini döndürür:

>>> class DictSubclass(dict):
...     def __repr__(self):
...         return "DictSubclass"
... 
>>> dict.fromkeys("abc")
{'a': None, 'c': None, 'b': None}
>>> DictSubclass.fromkeys("abc")
DictSubclass
>>> 

654
2017-09-25 21:05



Bir staticmethod işe yaramaz - bu, bir sınıfa bir fonksiyon koymanın bir yolu (mantıksal olarak oraya ait olduğu için), bu da sınıfa erişim gerektirmediğini gösterir. - Tony Meyer
Dolayısıyla sadece 'temelde' faydasız. Bu tür bir organizasyon, bağımlılık enjeksiyonunun yanı sıra, statik yöntemlerin geçerli kullanımlarıdır, ancak Java gibi sınıflar değil, modüller, Python'daki kod organizasyonunun temel öğeleri olduğundan, kullanımları ve yararlılıkları nadirdir. - Thomas Wouters
Bir sınıfın içinde ya da örnekleriyle ilgisi olmayan bir yöntemi tanımlamak mantıklı nedir? - Ben James
Belki miras uğruna? Statik yöntemler, örnek yöntem ve sınıf yöntemleri gibi kalıtsal ve geçersiz kılınabilir ve arama beklendiği gibi çalışır (Java'dan farklı olarak). Statik yöntemler, ister sınıf isterse de örnek olarak adlandırılırken statik olarak çözülemez, bu yüzden sınıf ve statik yöntemler arasındaki tek fark, örtük ilk argümandır. - haridsv
Ayrıca, daha temiz bir ad alanı oluştururlar ve işlevin sınıfla ilgili bir şeyleri anlamalarını kolaylaştırır. - Imbrondir


temel olarak @classmethod İlk argümanı, çağrıldığı sınıf (sınıf örneğinden ziyade) olan bir yöntem yapar. @staticmethodhiçbir dolaylı argüman yoktur.


110
2017-09-25 21:07





Resmi python belgeleri:

@classmethod

Bir sınıf yöntemi, sınıfı   örtük ilk argüman, tıpkı bir   örnek yöntemi örneği alır.   Bir sınıf yöntemini bildirmek için bunu kullanın   deyim:

class C:
    @classmethod
    def f(cls, arg1, arg2, ...): ... 

@classmethod form bir işlevdir    dekoratör - açıklamasına bakın   işlev tanımları fonksiyon   tanımlar detaylar için.

Bu sınıfta çağrılabilir   (gibi C.f()) veya bir örnekte   (gibi C().f()). Örnek   onun sınıfı hariç yok sayılır. Eğer bir   türetilmiş bir yöntem için çağrılır   sınıf, türetilmiş sınıf nesnesi   zımni ilk argüman olarak geçti.

Sınıf yöntemleri C ++ 'dan farklı   veya Java statik yöntemleri. Eğer istersen   bunlar, bakın staticmethod() bunda   Bölüm.

@staticmethod

Statik bir yöntem bir   örtülü ilk argüman. Beyan etmek   statik yöntem, bu deyimi kullanın:

class C:
    @staticmethod
    def f(arg1, arg2, ...): ... 

@staticmethod form bir işlevdir    dekoratör - açıklamasına bakın   işlev tanımları fonksiyon   tanımlar detaylar için.

Bu sınıfta çağrılabilir   (gibi C.f()) veya bir örnekte   (gibi C().f()). Örnek   onun sınıfı hariç yok sayılır.

Python'da statik yöntemler benzerdir   Java veya C ++'da bulunanlara. İçin   daha gelişmiş konsept, bkz    classmethod() bu bölümde.


76
2017-11-03 19:23





İşte bu soruyla ilgili kısa bir yazı

@staticmethod işlevi, bir sınıf içinde tanımlanan bir işlevden başka bir şey değildir. İlk önce dersi açmadan çağrılabilir. Bu tanım, kalıtım yoluyla değişmezdir.

@classmethod işlevi, aynı zamanda, sınıfın oluşturulmasına gerek kalmadan da kullanılabilir, ancak tanımı, sınıflandırma yoluyla Alt sınıf değil, Alt sınıfını izler. Bunun nedeni, @classmethod işlevi için ilk argümanın her zaman cl (sınıf) olması gerektiğidir.


55
2017-11-03 19:02



Yani bu, bir staticmethod kullanarak her zaman Ana sınıfa bağlı olduğum anlamına gelir ve classmethod ile (bu durumda alt sınıfta) classmethod bildirdiğim sınıfı bağlıyorum? - Mohan Gulati
Hayır. Bir staticmethod kullanarak hiç bağlı değilsiniz; örtük bir ilk parametre yoktur. Classmethod kullanarak, yöntemi çağırdığınız sınıfı (doğrudan bir sınıfa çağırdıysanız) veya yöntemi çağırdığınız örneğin sınıfını (bir örnekte çağırdıysanız) örtük ilk parametre olarak alırsınız. - Matt Anderson
Statik yöntemler yapmadığında (bunun için MyClass.attr kodlaması gerekir) sınıf yöntemlerinin bir birinci bağımsız değişken olarak bir sınıf oluşturarak, diğer sınıf özniteliklerine ve yöntemlerine doğrudan erişebildiğini göstermek için biraz genişletilebilir. - MestreLion


Kullanmaya karar vermek @staticmethod veya @classmethod yönteminizin içine bakmak zorundasınız. Yönteminiz, sınıfınızdaki diğer değişkenlere / yöntemlere erişiyorsa, @classmethod dosyasını kullanın.. Öte yandan, yönteminiz sınıfın başka bölümlerine dokunmuyorsa, @staticmethod öğesini kullanın.

class Apple:

    _counter = 0

    @staticmethod
    def about_apple():
        print('Apple is good for you.')

        # note you can still access other member of the class
        # but you have to use the class instance 
        # which is not very nice, because you have repeat yourself
        # 
        # For example:
        # @staticmethod
        #    print('Number of apples have been juiced: %s' % Apple._counter)
        #
        # @classmethod
        #    print('Number of apples have been juiced: %s' % cls._counter)
        #
        #    @classmethod is especially useful when you move your function to other class,
        #       you don't have to rename the class reference 

    @classmethod
    def make_apple_juice(cls, number_of_apples):
        print('Make juice:')
        for i in range(number_of_apples):
            cls._juice_this(i)

    @classmethod
    def _juice_this(cls, apple):
        print('Juicing %d...' % apple)
        cls._counter += 1

44
2018-04-22 15:40



Aslında statik yöntem örneğiniz yapar Bir sınıf değişkenine erişir. Örneğini geliştirebilirsin belki. - Cilyan


Python'da @staticmethod ve @classmethod arasındaki fark nedir?

Çeşitli yöntem türlerinin imzalarını gösteren ve her birini açıklayan bir belge sağlayan bu sözde kod gibi Python kodunu görmüş olabilirsiniz:

class Foo(object):

    def a_normal_instance_method(self, arg_1, kwarg_2=None):
        '''
        Return a value that is a function of the instance with its
        attributes, and other arguments such as arg_1 and kwarg2
        '''

    @staticmethod
    def a_static_method(arg_0):
        '''
        Return a value that is a function of arg_0. It does not know the 
        instance or class it is called from.
        '''

    @classmethod
    def a_class_method(cls, arg1):
        '''
        Return a value that is a function of the class and other arguments.
        respects subclassing, it is called with the class it is called from.
        '''

Normal Örnek Yöntemi

Önce ben açıklayacağım a_normal_instance_method. Bu tam olarak bir "denir"örnek yöntemÖrnek yöntem kullanıldığında, kısmi işlev olarak (kaynak kodda görüntülendiğinde tüm değerler için tanımlanan toplam bir işlevin aksine) kullanılır; bu, kullanıldığında, argümanların ilki örnek olarak önceden tanımlanır. nesnenin, verilen tüm özniteliklerle birlikte, kendisine bağlı nesnenin örneğine sahiptir ve nesnenin bir örneğinden çağrılmalıdır.Genel olarak, örneğin çeşitli özniteliklerine erişir.

Örneğin, bu bir dizenin örneğidir:

', '

Örnek yöntemini kullanırsak join Bu dizede, tekrarlanabilir başka bir katılmak için yinelenen listenin bir fonksiyonu olmasının yanı sıra, örneğin bir işlevi olduğu açıktır. ['a', 'b', 'c']:

>>> ', '.join(['a', 'b', 'c'])
'a, b, c'

Bağlı yöntemler

Örnek yöntemler daha sonra kullanmak için noktalı bir arama ile bağlanabilir.

Örneğin, bu bağlantıyı str.join yöntem ':' örnek:

>>> join_with_colons = ':'.join 

Ve sonra bunu zaten ona bağlı ilk argümana sahip bir işlev olarak kullanabiliriz. Bu şekilde, örnekte kısmi bir işlev gibi çalışır:

>>> join_with_colons('abcde')
'a:b:c:d:e'
>>> join_with_colons(['FF', 'FF', 'FF', 'FF', 'FF', 'FF'])
'FF:FF:FF:FF:FF:FF'

Statik Yöntem

Statik yöntem değil örneği bir argüman olarak ele alalım.

Bir modül seviyesi fonksiyonuna çok benzer.

Ancak, bir modül seviyesi fonksiyonu modülde yaşamalı ve kullanıldığı diğer yerlere özel olarak alınmalıdır.

Ancak, nesneye bağlıysa, nesneyi, ithalat ve miras yoluyla da uygun şekilde takip edecektir.

Statik bir yöntem örneği str.maketrans, taşındı string Python 3'te modül. Tüketim için uygun bir çeviri tablosu hazırlar. str.translate. Aşağıda gösterildiği gibi bir dizenin örneğinden kullanıldığında oldukça aptalca görünebilir, ancak işlevi string modül oldukça beceriksizdir ve onu sınıftan çağırmak güzeldir, str.maketrans

# demonstrate same function whether called from instance or not:
>>> ', '.maketrans('ABC', 'abc')
{65: 97, 66: 98, 67: 99}
>>> str.maketrans('ABC', 'abc')
{65: 97, 66: 98, 67: 99}

Python 2'de, bu işlevi giderek daha az kullanışlı olan dize modülünden almanız gerekir:

>>> import string
>>> 'ABCDEFG'.translate(string.maketrans('ABC', 'abc'))
'abcDEFG'

Sınıf yöntemi

Bir sınıf yöntemi, örtük bir ilk argümanı alması yerine bir örnek yöntemine benzer, ancak örneği almak yerine, sınıfı alır. Bunlar genellikle daha iyi anlamsal kullanım için alternatif kurucular olarak kullanılır ve kalıtımı destekleyecektir.

Yerleşik bir classmethod'un en kanonik örneği dict.fromkeys. Dict alternatif bir kurucu olarak kullanılır (anahtarlarınızın ne olduğunu bildiğinizde ve onlar için varsayılan bir değer istediğinde çok uygundur.)

>>> dict.fromkeys(['a', 'b', 'c'])
{'c': None, 'b': None, 'a': None}

Alt sınıfı belirlediğimizde, alt sınıfın bir örneğini oluşturan aynı kurucuyu kullanabiliriz.

>>> class MyDict(dict): 'A dict subclass, use to demo classmethods'
>>> md = MyDict.fromkeys(['a', 'b', 'c'])
>>> md
{'a': None, 'c': None, 'b': None}
>>> type(md)
<class '__main__.MyDict'>

Bakın pandalar kaynak kodu Alternatif kurucuların diğer benzer örnekleri için ve ayrıca resmi Python belgelerine bakınız. classmethod ve staticmethod.


38
2018-01-23 20:01





python 2.4'a @decorators eklendi. python <2.4 kullanıyorsanız, classmethod () ve staticmethod () işlevini kullanabilirsiniz.

Örneğin, bir fabrika yöntemi oluşturmak istiyorsanız (Ne tür bir argümana bağlı olarak bir sınıfın farklı bir uygulamasının bir örneğini döndüren bir işlev) aşağıdaki gibi bir şey yapabilirsiniz:

class Cluster(object):

    def _is_cluster_for(cls, name):
        """
        see if this class is the cluster with this name
        this is a classmethod
        """ 
        return cls.__name__ == name
    _is_cluster_for = classmethod(_is_cluster_for)

    #static method
    def getCluster(name):
        """
        static factory method, should be in Cluster class
        returns a cluster object for the given name
        """
        for cls in Cluster.__subclasses__():
            if cls._is_cluster_for(name):
                return cls()
    getCluster = staticmethod(getCluster)

Bunun bir classmethod ve statik bir metodu kullanmanın iyi bir örneği olduğunu da göz önünde bulundurun. Statik yöntem, sınıf Kümesini dahili olarak kullandığı için, sınıfa açıkça aittir. Classmethod sadece sınıf hakkında bilgi ve nesnenin hiçbir örneğine ihtiyaç duymaz.

Yapmanın bir başka faydası _is_cluster_for yöntem bir classmethod bu yüzden bir alt sınıf uygulamanın değiştirilmesine karar verebilir, belki de oldukça geneldir ve birden fazla küme türünü ele alabilir, bu yüzden sadece sınıfın ismini kontrol etmek yeterli olmaz.


27
2018-02-24 09:32





Bence daha iyi bir soru, "@classmethod vs @staticmethod'u ne zaman kullanırdınız?"

@classmethod, sınıf tanımına bağlı özel üyelere kolay erişim sağlar. Bu, oluşturulmuş nesnelerin örnek sayısını kontrol eden tekil veya fabrika sınıflarını yapmak için harika bir yoldur.

@staticmethod marjinal performans kazançları sağlar, ancak sınıfın dışında bağımsız bir işlev olarak elde edilemeyen bir sınıf içinde statik bir yöntemin üretken kullanımını henüz görmedim.


26
2018-05-19 15:27





Statik Yöntemler:

  • Öz argümanı olmayan basit fonksiyonlar.
  • Sınıf özellikleri üzerinde çalışmak; örnek nitelikleri değil.
  • Hem sınıf hem de örnek yoluyla çağrılabilir.
  • Yerleşik işlevi staticmethod () onları oluşturmak için kullanılır.

Statik Yöntemlerin Faydaları:

  • Classscope'un işlev adını lokalize eder
  • İşlev kodunu, kullanıldığı yere yaklaştırır.
  • Her bir yöntemin özel olarak içe aktarılması gerekmediğinden, modül düzeyinde işlevlere karşı içe aktarma için daha uygun

    @staticmethod
    def some_static_method(*args, **kwds):
        pass
    

Sınıf Yöntemleri:

  • Classname olarak ilk argümanı olan fonksiyonlar.
  • Hem sınıf hem de örnek yoluyla çağrılabilir.
  • Bunlar classmethod yerleşik işleviyle oluşturulur.

     @classmethod
     def some_class_method(cls, *args, **kwds):
         pass
    

23
2017-10-03 10:41