Pertanyaan Apa perbedaan antara @staticmethod dan @classmethod dengan Python?


Apa perbedaan antara fungsi yang dihias dengan @staticmethod dan satu dihiasi @classmethod?


2671
2017-09-25 21:01


asal


Jawaban:


Mungkin sedikit kode contoh akan membantu: Perhatikan perbedaan dalam tanda panggilan dari foo, class_foo dan 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()

Di bawah ini adalah cara biasa contoh objek memanggil metode. Instance objek, a, secara implisit dilewatkan sebagai argumen pertama.

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

Dengan metode kelas, kelas contoh objek secara implisit dilewatkan sebagai argumen pertama, bukan self.

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

Anda juga bisa menelepon class_foo menggunakan kelas. Bahkan, jika Anda mendefinisikan sesuatu sebuah metode kelas, mungkin karena Anda berniat untuk memanggilnya dari kelas daripada dari kelas contoh. A.foo(1) akan membangkitkan TypeError, tapi A.class_foo(1) bekerja dengan baik:

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

Satu penggunaan yang telah ditemukan orang untuk metode kelas adalah menciptakan konstruktor alternatif yang dapat diwariskan.


Dengan metode statis, juga tidak self (contoh objek) juga cls (kelas) secara implisit dilewatkan sebagai argumen pertama. Mereka berperilaku seperti fungsi biasa kecuali Anda dapat memanggil mereka dari instance atau kelas:

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

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

Metode statis digunakan untuk mengelompokkan fungsi yang memiliki koneksi logis dengan kelas ke kelas.


foo hanyalah sebuah fungsi, tetapi ketika Anda menelepon a.foo Anda tidak hanya mendapatkan fungsi itu, Anda mendapatkan versi "sebagian diterapkan" dari fungsi dengan objek contoh a terikat sebagai argumen pertama ke fungsi. foo mengharapkan 2 argumen, sementara a.foo hanya mengharapkan 1 argumen.

a pasti foo. Itulah yang dimaksud dengan istilah "terikat" di bawah ini:

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

Dengan a.class_foo, a tidak terikat class_foo, bukan kelasnya A pasti class_foo.

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

Di sini, dengan metode statis, meskipun itu adalah metode, a.static_foo baru kembali fungsi ole yang bagus tanpa argumen terikat. static_foo mengharapkan 1 argumen, dan a.static_foo mengharapkan 1 argumen juga.

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

Dan tentu saja hal yang sama terjadi ketika Anda menelepon static_foo dengan kelas A sebagai gantinya.

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

2316
2017-11-03 19:13



SEBUAH metode statis adalah metode yang tidak tahu apa-apa tentang kelas atau contoh yang dipanggil. Itu hanya mendapatkan argumen yang disahkan, tidak ada argumen pertama yang implisit. Ini pada dasarnya tidak berguna dalam Python - Anda bisa menggunakan fungsi modul, bukan statis.

SEBUAH classmethod, di sisi lain, adalah metode yang melewati kelas yang disebut, atau kelas dari instance yang dipanggil, sebagai argumen pertama. Ini berguna ketika Anda ingin metode menjadi pabrik untuk kelas: karena mendapat kelas yang sebenarnya disebut sebagai argumen pertama, Anda selalu dapat memberi contoh kelas yang tepat, bahkan ketika subclass terlibat. Amati misalnya bagaimana dict.fromkeys(), sebuah metode kelas, mengembalikan turunan subkelas saat dipanggil ke subkelas:

>>> 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



Pada dasarnya @classmethod membuat metode yang argumen pertamanya adalah kelas yang dipanggil dari (bukan instance kelas), @staticmethodtidak memiliki argumen implisit.


110
2017-09-25 21:07



Dokumen python resmi:

@classmethod

Metode kelas menerima kelas sebagai   argumen pertama implisit, seperti sebuah   metode instan menerima instance.   Untuk mendeklarasikan metode kelas, gunakan ini   idiom:

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

Itu @classmethod bentuk adalah fungsi    penghias - lihat deskripsi   definisi fungsi dalam Fungsi   definisi untuk detailnya.

Itu bisa disebut di kelas   (seperti C.f()) atau pada suatu contoh   (seperti C().f()). Contohnya adalah   diabaikan kecuali untuk kelasnya. Jika sebuah   metode kelas disebut untuk diturunkan   kelas, objek kelas turunan adalah   disahkan sebagai argumen pertama yang tersirat.

Metode kelas berbeda dari C ++   atau metode statis Java. jika kamu mau   mereka, lihat staticmethod() di dalam   bagian.

@staticmethod

Metode statis tidak menerima   argumen pertama implisit. Untuk menyatakan a   metode statis, gunakan idiom ini:

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

Itu @staticmethod bentuk adalah fungsi    penghias - lihat deskripsi   definisi fungsi dalam Fungsi   definisi untuk detailnya.

Itu bisa disebut di kelas   (seperti C.f()) atau pada suatu contoh   (seperti C().f()). Contohnya adalah   diabaikan kecuali untuk kelasnya.

Metode statis dengan Python serupa   untuk yang ditemukan di Java atau C ++. Untuk sebuah   konsep yang lebih maju, lihat    classmethod() di bagian ini.


76
2017-11-03 19:23



Sini adalah artikel singkat tentang pertanyaan ini

Fungsi @staticmethod tidak lebih dari fungsi yang didefinisikan di dalam kelas. Itu bisa dipanggil tanpa instantiate kelas pertama. Definisi ini tidak dapat diubah melalui pewarisan.

Fungsi @classmethod juga dapat dipanggil tanpa instantiate kelas, tetapi definisinya mengikuti kelas Sub, bukan kelas Parent, melalui warisan. Itu karena argumen pertama untuk fungsi @classmethod harus selalu cls (kelas).


55
2017-11-03 19:02



Untuk memutuskan apakah akan digunakan @staticmethod atau @classmethod Anda harus melihat ke dalam metode Anda. Jika metode Anda mengakses variabel / metode lain di kelas Anda, gunakan @classmethod. Di sisi lain, jika metode Anda tidak menyentuh bagian lain dari kelas, gunakan @staticmethod.

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



Apa perbedaan antara @staticmethod dan @classmethod dengan Python?

Anda mungkin telah melihat kode Python seperti pseudocode ini, yang menunjukkan tanda tangan dari berbagai jenis metode dan menyediakan dokumentasi untuk menjelaskan masing-masing:

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.
        '''

Metode Instance Normal

Pertama saya akan menjelaskan a_normal_instance_method. Ini tepatnya disebut "metode instan". Ketika suatu metode instance digunakan, digunakan sebagai fungsi parsial (sebagai lawan dari fungsi total, yang didefinisikan untuk semua nilai ketika dilihat dalam kode sumber) yang, ketika digunakan, yang pertama dari argumen yang telah ditetapkan sebagai contoh dari objek, dengan semua atribut yang diberikan. Ini memiliki contoh objek yang terikat padanya, dan itu harus dipanggil dari sebuah instance objek. Biasanya, ia akan mengakses berbagai atribut dari instance.

Misalnya, ini adalah turunan dari string:

', '

jika kita menggunakan metode instan, join pada string ini, untuk bergabung dengan iterable lain, itu cukup jelas adalah fungsi dari instance, selain menjadi fungsi dari daftar iterable, ['a', 'b', 'c']:

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

Metode terikat

Instance metode dapat terikat melalui pencarian bertitik untuk digunakan nanti.

Misalnya, ini mengikat str.join metode ke ':' contoh:

>>> join_with_colons = ':'.join 

Dan kemudian kita dapat menggunakan ini sebagai fungsi yang sudah memiliki argumen pertama yang terikat padanya. Dengan cara ini, ia berfungsi seperti fungsi parsial pada instance:

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

Metode Statis

Metode statis tidak tidak mengambil contoh sebagai argumen.

Ini sangat mirip dengan fungsi level modul.

Namun, fungsi level modul harus hidup dalam modul dan secara khusus diimpor ke tempat lain di mana ia digunakan.

Jika itu melekat pada objek, bagaimanapun, itu akan mengikuti objek dengan mudah melalui impor dan pewarisan juga.

Contoh dari metode statis str.maketrans, pindah dari string modul dengan Python 3. Ini membuat tabel terjemahan cocok untuk konsumsi oleh str.translate. Ini memang agak konyol ketika digunakan dari sebuah instance string, seperti yang ditunjukkan di bawah ini, tetapi mengimpor fungsi dari string Modul agak kikuk, dan itu bagus untuk dapat menyebutnya dari kelas, seperti dalam 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}

Dalam python 2, Anda harus mengimpor fungsi ini dari modul string yang kurang bermanfaat:

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

Metode Kelas

Metode kelas mirip dengan metode instan karena menggunakan argumen pertama yang implisit, tetapi alih-alih mengambil contoh, ia mengambil kelas. Sering ini digunakan sebagai konstruktor alternatif untuk penggunaan semantik yang lebih baik dan akan mendukung warisan.

Contoh paling kanonik dari metode kelas yang dibangun adalah dict.fromkeys. Ini digunakan sebagai konstruktor alternatif dari dict, (sangat cocok untuk ketika Anda tahu apa kunci Anda dan menginginkan nilai default untuk mereka.)

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

Ketika kita subclass dict, kita bisa menggunakan konstruktor yang sama, yang membuat turunan dari subclass.

>>> 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'>

Lihat kode sumber panda untuk contoh lain yang serupa dari konstruktor alternatif, dan lihat juga dokumentasi resmi Python classmethod dan staticmethod.


38
2018-01-23 20:01



@decorators ditambahkan dalam python 2.4 Jika Anda menggunakan python <2.4 Anda dapat menggunakan fungsi classmethod () dan staticmethod ().

Misalnya, jika Anda ingin membuat metode pabrik (fungsi A mengembalikan instance dari implementasi kelas yang berbeda tergantung pada argumen apa yang didapatkan) Anda dapat melakukan sesuatu seperti:

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)

Perhatikan juga bahwa ini adalah contoh yang baik untuk menggunakan metode kelas dan metode statis, Metode statis jelas milik kelas, karena menggunakan kelas Cluster secara internal. Classmethod hanya membutuhkan informasi tentang kelas, dan tidak ada contoh objek.

Manfaat lain dari pembuatan _is_cluster_for metode classmethod sangat subclass dapat memutuskan untuk mengubah implementasi itu, mungkin karena cukup generik dan dapat menangani lebih dari satu jenis cluster, jadi hanya memeriksa nama kelas tidak akan cukup.


27
2018-02-24 09:32



Saya pikir pertanyaan yang lebih baik adalah "Kapan Anda menggunakan @classmethod vs @staticmethod?"

@classmethod memungkinkan Anda akses mudah ke anggota pribadi yang terkait dengan definisi kelas. ini adalah cara yang bagus untuk melakukan lajang, atau kelas pabrik yang mengontrol jumlah instance dari objek yang dibuat ada.

@staticmethod memberikan keuntungan kinerja marjinal, tetapi saya belum melihat penggunaan metode statis yang produktif dalam kelas yang tidak dapat dicapai sebagai fungsi mandiri di luar kelas.


26
2018-05-19 15:27