Apa perbedaan antara fungsi yang didekorasi dengan yang @staticmethod
didekorasi @classmethod
?
Apa perbedaan antara fungsi yang didekorasi dengan yang @staticmethod
didekorasi @classmethod
?
Jawaban:
Mungkin sedikit contoh kode akan membantu: Perhatikan perbedaan tanda tangan panggilan 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 instance instance memanggil metode. Contoh objek,, a
secara implisit disahkan sebagai argumen pertama.
a.foo(1)
# executing foo(<__main__.A object at 0xb7dbef0c>,1)
Dengan classmethods , kelas instance objek secara implisit dilewatkan sebagai argumen pertama alih-alih self
.
a.class_foo(1)
# executing class_foo(<class '__main__.A'>,1)
Anda juga dapat menelepon class_foo
menggunakan kelas. Bahkan, jika Anda mendefinisikan sesuatu sebagai metode kelas, itu mungkin karena Anda bermaksud menyebutnya dari kelas daripada dari instance kelas. A.foo(1)
akan mengangkat TypeError, tetapi A.class_foo(1)
berfungsi dengan baik:
A.class_foo(1)
# executing class_foo(<class '__main__.A'>,1)
Satu kegunaan yang ditemukan orang untuk metode kelas adalah membuat konstruktor alternatif yang dapat diwariskan .
Dengan metode statis , baik self
(objek contoh) maupun cls
(kelas) secara implisit dilewatkan sebagai argumen pertama. Mereka berperilaku seperti fungsi sederhana kecuali bahwa 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 beberapa koneksi logis dengan kelas ke kelas.
foo
hanya sebuah fungsi, tetapi ketika Anda menelepon a.foo
Anda tidak hanya mendapatkan fungsi, Anda mendapatkan versi "sebagian diterapkan" dari fungsi dengan instance instance objek a
terikat sebagai argumen pertama ke fungsi. foo
mengharapkan 2 argumen, sementara a.foo
hanya mengharapkan 1 argumen.
a
terikat foo
. Itulah yang dimaksud dengan istilah "terikat" di bawah:
print(a.foo)
# <bound method A.foo of <__main__.A object at 0xb7d52f0c>>
Dengan a.class_foo
, a
tidak terikat class_foo
, melainkan kelas A
terikat class_foo
.
print(a.class_foo)
# <bound method type.class_foo of <class '__main__.A'>>
Di sini, dengan metode statis, meskipun metode, a.static_foo
hanya mengembalikan fungsi yang baik 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>
@staticmethod
mungkin membantu mengatur kode Anda dengan ditimpa oleh subclass. Tanpanya Anda akan memiliki varian fungsi yang melayang-layang di namespace modul.
@staticmethod
- Anda dapat menggunakannya untuk menghapus cruft. Saya menerapkan bahasa pemrograman dengan Python - fungsi-fungsi yang ditentukan-perpustakaan menggunakan execute
metode statis , di mana fungsi-fungsi yang ditentukan pengguna memerlukan argumen instance (yaitu, badan fungsi). Penghias ini menghilangkan peringatan "parameter diri yang tidak digunakan" di inspektur PyCharm.
Metode statis adalah metode yang tidak tahu apa-apa tentang kelas atau instance yang dipanggilnya. Hanya mendapat argumen yang disahkan, tidak ada argumen pertama tersirat. Ini pada dasarnya tidak berguna dalam Python - Anda bisa menggunakan fungsi modul bukan metode statis.
Sebuah classmethod , di sisi lain, adalah metode yang akan lulus kelas itu dipanggil, atau kelas dari contoh itu disebut pada, sebagai argumen pertama. Ini berguna ketika Anda ingin metode menjadi pabrik untuk kelas: karena mendapatkan kelas aktual yang dipanggil sebagai argumen pertama, Anda selalu dapat membuat instance kelas yang tepat, bahkan ketika subclass terlibat. Perhatikan misalnya bagaimana dict.fromkeys()
suatu metode kelas, mengembalikan sebuah instance dari subclass ketika dipanggil pada sebuah subclass:
>>> class DictSubclass(dict):
... def __repr__(self):
... return "DictSubclass"
...
>>> dict.fromkeys("abc")
{'a': None, 'c': None, 'b': None}
>>> DictSubclass.fromkeys("abc")
DictSubclass
>>>
Pada dasarnya @classmethod
membuat metode yang argumen pertamanya adalah kelas dari mana (bukan dari instance kelas), @staticmethod
tidak memiliki argumen implisit.
Dokumen python resmi:
Metode kelas menerima kelas sebagai argumen pertama implisit, seperti metode instance menerima instance. Untuk mendeklarasikan metode kelas, gunakan idiom ini:
class C: @classmethod def f(cls, arg1, arg2, ...): ...
The
@classmethod
bentuk adalah fungsi dekorator - lihat deskripsi definisi fungsi dalam Fungsi definisi untuk rincian.Itu dapat dipanggil baik di kelas (seperti
C.f()
) atau pada instance (sepertiC().f()
). Instance diabaikan kecuali untuk kelasnya. Jika metode kelas dipanggil untuk kelas turunan, objek kelas turunan dilewatkan sebagai argumen pertama yang tersirat.Metode kelas berbeda dari metode C ++ atau Java statis. Jika Anda menginginkannya, lihat
staticmethod()
di bagian ini.
Metode statis tidak menerima argumen pertama implisit. Untuk mendeklarasikan metode statis, gunakan idiom ini:
class C: @staticmethod def f(arg1, arg2, ...): ...
The
@staticmethod
bentuk adalah fungsi dekorator - lihat deskripsi definisi fungsi dalam Fungsi definisi untuk rincian.Itu dapat dipanggil baik di kelas (seperti
C.f()
) atau pada instance (sepertiC().f()
). Instance diabaikan kecuali untuk kelasnya.Metode statis dengan Python mirip dengan yang ditemukan di Java atau C ++. Untuk konsep yang lebih maju, lihat
classmethod()
di bagian ini.
Berikut adalah artikel singkat tentang pertanyaan ini
@staticmethod function tidak lebih dari fungsi yang didefinisikan di dalam kelas. Itu bisa dipanggil tanpa membuat instance kelas terlebih dahulu. Definisi itu tidak dapat diubah melalui pewarisan.
Fungsi @classmethod juga dapat dipanggil tanpa membuat instance kelas, tetapi definisinya mengikuti Sub kelas, bukan kelas Induk, melalui pewarisan. Itu karena argumen pertama untuk fungsi @classmethod harus selalu cls (class).
Untuk memutuskan apakah akan menggunakan @staticmethod atau @classmethod, Anda harus melihat ke dalam metode Anda. Jika metode Anda mengakses variabel / metode lain di kelas Anda maka gunakan @classmethod . Di sisi lain, jika metode Anda tidak menyentuh bagian lain dari kelas maka 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
cls._counter
masih akan menjadi cls._counter
bahkan jika kode tersebut diletakkan di kelas yang berbeda, atau nama kelas diubah. Apple._counter
khusus untuk Apple
kelas; untuk kelas yang berbeda, atau ketika nama kelas diubah, Anda perlu mengubah kelas yang direferensikan.
Apa perbedaan antara @staticmethod dan @classmethod dalam Python?
Anda mungkin telah melihat kode Python seperti pseudocode ini, yang menunjukkan tanda tangan dari berbagai jenis metode dan menyediakan docstring 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.
'''
Pertama saya akan jelaskan a_normal_instance_method
. Ini tepatnya disebut " metode contoh ". Ketika metode instance digunakan, digunakan sebagai fungsi parsial (sebagai lawan dari fungsi total, didefinisikan untuk semua nilai bila dilihat dalam kode sumber) yaitu, ketika digunakan, argumen pertama ditentukan sebelumnya sebagai instance dari objek, dengan semua atribut yang diberikannya. Ia memiliki instance dari objek yang terikat padanya, dan itu harus dipanggil dari instance objek. Biasanya, itu akan mengakses berbagai atribut instance.
Misalnya, ini adalah instance dari string:
', '
jika kita menggunakan metode contoh, join
pada string ini, untuk bergabung dengan yang lain iterable, itu cukup jelas adalah fungsi dari contoh, selain menjadi fungsi dari daftar iterable, ['a', 'b', 'c']
:
>>> ', '.join(['a', 'b', 'c'])
'a, b, c'
Metode instan dapat diikat melalui pencarian bertitik untuk digunakan nanti.
Misalnya, ini mengikat str.join
metode ke ':'
instance:
>>> join_with_colons = ':'.join
Dan nanti kita bisa menggunakan ini sebagai fungsi yang sudah memiliki argumen pertama terikat padanya. Dengan cara ini, ini 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 tidak mengambil contoh sebagai argumen.
Ini sangat mirip dengan fungsi level modul.
Namun, fungsi level modul harus hidup dalam modul dan diimpor secara khusus ke tempat lain di mana ia digunakan.
Namun, jika itu melekat pada objek, ia akan mengikuti objek dengan nyaman melalui impor dan pewarisan juga.
Contoh metode statis adalah str.maketrans
, dipindahkan dari string
modul dengan Python 3. Itu membuat tabel terjemahan cocok untuk dikonsumsi oleh str.translate
. Tampaknya agak konyol ketika digunakan dari instance string, seperti yang ditunjukkan di bawah ini, tetapi mengimpor fungsi dari string
modul agak canggung, dan senang bisa menyebutnya dari kelas, seperti padastr.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 semakin tidak berguna:
>>> import string
>>> 'ABCDEFG'.translate(string.maketrans('ABC', 'abc'))
'abcDEFG'
Metode kelas mirip dengan metode instance dalam mengambil argumen pertama implisit, tetapi alih-alih mengambil instance, dibutuhkan kelas. Seringkali ini digunakan sebagai konstruktor alternatif untuk penggunaan semantik yang lebih baik dan akan mendukung warisan.
Contoh paling kanonik dari metode kelas builtin adalah dict.fromkeys
. Ini digunakan sebagai konstruktor alternatif dict, (cocok untuk ketika Anda tahu apa kunci Anda dan ingin nilai default untuk mereka.)
>>> dict.fromkeys(['a', 'b', 'c'])
{'c': None, 'b': None, 'a': None}
Ketika kita subclass dict, kita dapat 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 serupa lainnya dari konstruktor alternatif, dan lihat juga dokumentasi Python resmi pada classmethod
dan staticmethod
.
Saya mulai belajar bahasa pemrograman dengan C ++ dan kemudian Java dan kemudian Python dan pertanyaan ini sangat mengganggu saya, sampai saya mengerti penggunaan sederhana masing-masing.
Metode Kelas: Python tidak seperti Java dan C ++ tidak memiliki konstruktor yang berlebihan. Maka untuk mencapai ini Anda bisa menggunakan classmethod
. Contoh berikut akan menjelaskan hal ini
Mari kita anggap kita memiliki Person
kelas yang membutuhkan dua argumen first_name
dan last_name
dan menciptakan instance dari Person
.
class Person(object):
def __init__(self, first_name, last_name):
self.first_name = first_name
self.last_name = last_name
Sekarang, jika persyaratan datang di mana Anda perlu membuat kelas menggunakan satu nama saja, hanya a first_name
, Anda tidak dapat melakukan sesuatu seperti ini dengan Python.
Ini akan memberi Anda kesalahan ketika Anda akan mencoba membuat objek (contoh).
class Person(object):
def __init__(self, first_name, last_name):
self.first_name = first_name
self.last_name = last_name
def __init__(self, first_name):
self.first_name = first_name
Namun, Anda dapat mencapai hal yang sama menggunakan @classmethod
seperti yang disebutkan di bawah ini
class Person(object):
def __init__(self, first_name, last_name):
self.first_name = first_name
self.last_name = last_name
@classmethod
def get_person(cls, first_name):
return cls(first_name, "")
Metode Statis: Ini agak sederhana, tidak terikat pada instance atau kelas dan Anda dapat memanggilnya menggunakan nama kelas.
Jadi katakanlah dalam contoh di atas Anda memerlukan validasi yang first_name
tidak boleh melebihi 20 karakter, Anda cukup melakukan ini.
@staticmethod
def validate_name(name):
return len(name) <= 20
dan Anda cukup menelepon menggunakan class name
Person.validate_name("Gaurang Shah")
def __init__(self, first_name, last_name="")
bukan metode kelas get_person
. Hasilnya juga akan persis sama dalam kasus ini.
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 terbaik untuk melakukan lajang, atau kelas pabrik yang mengontrol jumlah instance dari objek yang dibuat yang ada.
@staticmethod memberikan keuntungan kinerja marjinal, tapi saya belum melihat penggunaan produktif metode statis dalam kelas yang tidak dapat dicapai sebagai fungsi mandiri di luar kelas.
@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 yang mengembalikan instance dari implementasi kelas yang berbeda tergantung pada argumen yang didapatnya), 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 class dan metode statis, Metode statis jelas milik kelas, karena menggunakan Cluster kelas secara internal. Metode class hanya membutuhkan informasi tentang kelas, dan tidak ada instance dari objek.
Manfaat lain dari membuat _is_cluster_for
metode metodemetode adalah agar subkelas dapat memutuskan untuk mengubah implementasinya, mungkin karena cukup generik dan dapat menangani lebih dari satu jenis kluster, jadi hanya memeriksa nama kelas tidak akan cukup.
Metode Statis:
Manfaat Metode Statis:
Lebih nyaman untuk mengimpor versus fungsi tingkat modul karena setiap metode tidak harus diimpor secara khusus
@staticmethod
def some_static_method(*args, **kwds):
pass
Metode Kelas:
Ini dibuat dengan classmethod in-built function.
@classmethod
def some_class_method(cls, *args, **kwds):
pass
@staticmethod
hanya menonaktifkan fungsi default sebagai deskriptor metode. classmethod membungkus fungsi Anda dalam sebuah wadah yang bisa dipanggil yang meneruskan referensi ke kelas pemilik sebagai argumen pertama:
>>> class C(object):
... pass
...
>>> def f():
... pass
...
>>> staticmethod(f).__get__(None, C)
<function f at 0x5c1cf0>
>>> classmethod(f).__get__(None, C)
<bound method type.f of <class '__main__.C'>>
Sebenarnya, classmethod
memiliki overhead runtime tetapi memungkinkan untuk mengakses kelas pemilik. Atau saya sarankan menggunakan metaclass dan meletakkan metode kelas pada metaclass itu:
>>> class CMeta(type):
... def foo(cls):
... print cls
...
>>> class C(object):
... __metaclass__ = CMeta
...
>>> C.foo()
<class '__main__.C'>
c = C(); c.foo()
memunculkan AttributeError, yang harus Anda lakukan type(c).foo()
. Ini mungkin juga dianggap sebagai fitur - saya tidak bisa memikirkan mengapa Anda ingin melakukannya.
Panduan pasti tentang cara menggunakan metode statis, kelas atau abstrak dengan Python adalah salah satu tautan yang bagus untuk topik ini, dan rangkum sebagai berikut.
@staticmethod
fungsi tidak lebih dari fungsi yang didefinisikan di dalam kelas. Itu bisa dipanggil tanpa membuat instance kelas terlebih dahulu. Definisi itu tidak dapat diubah melalui pewarisan.
@classmethod
fungsi juga dapat dipanggil tanpa membuat instance kelas, tetapi definisinya mengikuti Sub kelas, bukan kelas Induk, melalui pewarisan, dapat ditimpa oleh subclass. Itu karena argumen pertama untuk @classmethod
fungsi harus selalu cls (class).
Hanya argumen pertama yang berbeda :
Lebih detail ...
Ketika metode objek dipanggil, ia secara otomatis diberikan argumen tambahan self
sebagai argumen pertamanya. Yaitu, metode
def f(self, x, y)
harus dipanggil dengan 2 argumen. self
secara otomatis berlalu, dan itu adalah objek itu sendiri .
Ketika metode tersebut didekorasi
@classmethod
def f(cls, x, y)
argumen yang disediakan secara otomatis bukan self
, tetapi kelas self
.
Ketika metode tersebut didekorasi
@staticmethod
def f(x, y)
metode ini tidak diberikan argumen otomatis sama sekali. Hanya diberikan parameter yang dipanggil dengan.
classmethod
sebagian besar digunakan untuk konstruktor alternatif. staticmethod
tidak menggunakan status objek. Ini bisa menjadi fungsi eksternal untuk kelas. Itu hanya dimasukkan ke dalam kelas untuk mengelompokkan fungsi-fungsi dengan fungsi yang serupa (misalnya, seperti Math
metode statis kelas Java )class Point
def __init__(self, x, y):
self.x = x
self.y = y
@classmethod
def frompolar(cls, radius, angle):
"""The `cls` argument is the `Point` class itself"""
return cls(radius * cos(angle), radius * sin(angle))
@staticmethod
def angle(x, y):
"""this could be outside the class, but we put it here
just because we think it is logically related to the class."""
return atan(y, x)
p1 = Point(3, 2)
p2 = Point.frompolar(3, pi/4)
angle = Point.angle(3, 2)
Biarkan saya memberitahu kesamaan antara metode yang dihiasi dengan @classmethod vs @staticmethod terlebih dahulu.
Kesamaan: Keduanya dapat dipanggil di Kelas itu sendiri, bukan hanya contoh kelas. Jadi, keduanya merupakan metode Kelas .
Perbedaan: Metode kelas akan menerima kelas itu sendiri sebagai argumen pertama, sedangkan metode statis tidak.
Jadi metode statis, dalam arti tertentu, tidak terikat pada Kelas itu sendiri dan hanya menggantung di sana hanya karena mungkin memiliki fungsi terkait.
>>> class Klaus:
@classmethod
def classmthd(*args):
return args
@staticmethod
def staticmthd(*args):
return args
# 1. Call classmethod without any arg
>>> Klaus.classmthd()
(__main__.Klaus,) # the class gets passed as the first argument
# 2. Call classmethod with 1 arg
>>> Klaus.classmthd('chumma')
(__main__.Klaus, 'chumma')
# 3. Call staticmethod without any arg
>>> Klaus.staticmthd()
()
# 4. Call staticmethod with 1 arg
>>> Klaus.staticmthd('chumma')
('chumma',)
Pertimbangan lain sehubungan dengan staticmethod vs classmethod muncul dengan warisan. Katakanlah Anda memiliki kelas berikut:
class Foo(object):
@staticmethod
def bar():
return "In Foo"
Dan Anda kemudian ingin menimpa bar()
di kelas anak:
class Foo2(Foo):
@staticmethod
def bar():
return "In Foo2"
Ini berfungsi, tetapi perhatikan bahwa sekarang bar()
implementasi di kelas anak ( Foo2
) tidak dapat lagi memanfaatkan apa pun yang spesifik untuk kelas itu. Misalnya, katakan Foo2
memiliki metode yang disebut magic()
yang ingin Anda gunakan dalam Foo2
implementasi bar()
:
class Foo2(Foo):
@staticmethod
def bar():
return "In Foo2"
@staticmethod
def magic():
return "Something useful you'd like to use in bar, but now can't"
Solusi di sini akan memanggil Foo2.magic()
di bar()
, tapi kemudian Anda mengulangi diri sendiri (jika nama Foo2
perubahan, Anda harus ingat untuk memperbarui bahwa bar()
metode).
Bagi saya, ini adalah sedikit pelanggaran prinsip terbuka / tertutup , karena keputusan yang dibuat Foo
berdampak pada kemampuan Anda untuk memperbaiki kode umum di kelas turunan (yaitu kurang terbuka untuk ekstensi). Jika bar()
a classmethod
kita akan baik-baik saja:
class Foo(object):
@classmethod
def bar(cls):
return "In Foo"
class Foo2(Foo):
@classmethod
def bar(cls):
return "In Foo2 " + cls.magic()
@classmethod
def magic(cls):
return "MAGIC"
print Foo2().bar()
Memberi: In Foo2 MAGIC
Saya akan mencoba menjelaskan perbedaan dasar menggunakan contoh.
class A(object):
x = 0
def say_hi(self):
pass
@staticmethod
def say_hi_static():
pass
@classmethod
def say_hi_class(cls):
pass
def run_self(self):
self.x += 1
print self.x # outputs 1
self.say_hi()
self.say_hi_static()
self.say_hi_class()
@staticmethod
def run_static():
print A.x # outputs 0
# A.say_hi() # wrong
A.say_hi_static()
A.say_hi_class()
@classmethod
def run_class(cls):
print cls.x # outputs 0
# cls.say_hi() # wrong
cls.say_hi_static()
cls.say_hi_class()
1 - kita dapat langsung memanggil metode statis dan metode tanpa menginisialisasi
# A.run_self() # wrong
A.run_static()
A.run_class()
2- Metode statis tidak dapat memanggil metode mandiri tetapi dapat memanggil metode statis dan metode lainnya
3 - Metode statis milik kelas dan tidak akan menggunakan objek sama sekali.
4- Metode kelas tidak terikat pada objek tetapi ke kelas.
@classmethod: dapat digunakan untuk membuat akses global bersama ke semua instance yang dibuat dari kelas itu ..... seperti memperbarui catatan oleh banyak pengguna .... Saya khususnya menemukan itu menggunakan ful saat membuat lajang juga ..: )
@static method: tidak ada hubungannya dengan kelas atau instance yang dikaitkan dengan ... tetapi untuk keterbacaan dapat menggunakan metode statis
Anda mungkin ingin mempertimbangkan perbedaan antara:
Class A:
def foo(): # no self parameter, no decorator
pass
dan
Class B:
@staticmethod
def foo(): # no self parameter
pass
Ini telah berubah antara python2 dan python3:
python2:
>>> A.foo()
TypeError
>>> A().foo()
TypeError
>>> B.foo()
>>> B().foo()
python3:
>>> A.foo()
>>> A().foo()
TypeError
>>> B.foo()
>>> B().foo()
Jadi menggunakan @staticmethod
metode yang hanya dipanggil langsung dari kelas telah menjadi opsional di python3. Jika Anda ingin memanggil mereka dari kelas dan instance, Anda masih perlu menggunakan @staticmethod
dekorator.
Kasus-kasus lain telah dicakup oleh jawaban unutbus
Metode kelas menerima kelas sebagai argumen pertama implisit, seperti metode instance menerima instance. Ini adalah metode yang terikat ke kelas dan bukan objek dari kelas. Ini memiliki akses ke keadaan kelas karena mengambil parameter kelas yang menunjuk ke kelas dan bukan objek contoh. Itu dapat memodifikasi status kelas yang akan berlaku di semua instance kelas. Misalnya ia dapat memodifikasi variabel kelas yang akan berlaku untuk semua instance.
Di sisi lain, metode statis tidak menerima argumen pertama implisit, dibandingkan dengan metode kelas atau metode instance. Dan tidak dapat mengakses atau mengubah status kelas. Itu hanya milik kelas karena dari sudut pandang desain itu adalah cara yang benar. Tetapi dalam hal fungsi tidak terikat, saat runtime, ke kelas.
sebagai pedoman, gunakan metode statis sebagai utilitas, gunakan metode kelas misalnya sebagai pabrik. Atau mungkin untuk mendefinisikan singleton. Dan gunakan metode instan untuk memodelkan keadaan dan perilaku instance.
Semoga saya jelas!
Kontribusi saya menunjukkan perbedaan antara @classmethod
,, @staticmethod
dan metode instance, termasuk bagaimana sebuah instance dapat secara tidak langsung memanggil a @staticmethod
. Tetapi alih-alih secara tidak langsung memanggil @staticmethod
dari suatu contoh, menjadikannya pribadi mungkin lebih "pythonic." Mendapatkan sesuatu dari metode pribadi tidak ditunjukkan di sini tetapi pada dasarnya konsep yang sama.
#!python3
from os import system
system('cls')
# % % % % % % % % % % % % % % % % % % % %
class DemoClass(object):
# instance methods need a class instance and
# can access the instance through 'self'
def instance_method_1(self):
return 'called from inside the instance_method_1()'
def instance_method_2(self):
# an instance outside the class indirectly calls the static_method
return self.static_method() + ' via instance_method_2()'
# class methods don't need a class instance, they can't access the
# instance (self) but they have access to the class itself via 'cls'
@classmethod
def class_method(cls):
return 'called from inside the class_method()'
# static methods don't have access to 'cls' or 'self', they work like
# regular functions but belong to the class' namespace
@staticmethod
def static_method():
return 'called from inside the static_method()'
# % % % % % % % % % % % % % % % % % % % %
# works even if the class hasn't been instantiated
print(DemoClass.class_method() + '\n')
''' called from inside the class_method() '''
# works even if the class hasn't been instantiated
print(DemoClass.static_method() + '\n')
''' called from inside the static_method() '''
# % % % % % % % % % % % % % % % % % % % %
# >>>>> all methods types can be called on a class instance <<<<<
# instantiate the class
democlassObj = DemoClass()
# call instance_method_1()
print(democlassObj.instance_method_1() + '\n')
''' called from inside the instance_method_1() '''
# # indirectly call static_method through instance_method_2(), there's really no use
# for this since a @staticmethod can be called whether the class has been
# instantiated or not
print(democlassObj.instance_method_2() + '\n')
''' called from inside the static_method() via instance_method_2() '''
# call class_method()
print(democlassObj.class_method() + '\n')
''' called from inside the class_method() '''
# call static_method()
print(democlassObj.static_method())
''' called from inside the static_method() '''
"""
# whether the class is instantiated or not, this doesn't work
print(DemoClass.instance_method_1() + '\n')
'''
TypeError: TypeError: unbound method instancemethod() must be called with
DemoClass instance as first argument (got nothing instead)
'''
"""
Metode kelas, seperti namanya, digunakan untuk membuat perubahan pada kelas dan bukan objek. Untuk membuat perubahan pada kelas, mereka akan memodifikasi atribut kelas (bukan atribut objek), karena itulah cara Anda memperbarui kelas. Ini adalah alasan bahwa metode kelas mengambil kelas (secara konvensional dilambangkan oleh 'cls') sebagai argumen pertama.
class A(object):
m=54
@classmethod
def class_method(cls):
print "m is %d" % cls.m
Metode statis di sisi lain, digunakan untuk melakukan fungsionalitas yang tidak terikat ke kelas yaitu mereka tidak akan membaca atau menulis variabel kelas. Oleh karena itu, metode statis tidak mengambil kelas sebagai argumen. Mereka digunakan sehingga kelas dapat melakukan fungsi yang tidak terkait langsung dengan tujuan kelas.
class X(object):
m=54 #will not be referenced
@staticmethod
def static_method():
print "Referencing/calling a variable or function outside this class. E.g. Some global variable/function."
Menganalisis @staticmethod secara harfiah memberikan wawasan yang berbeda.
Metode normal kelas adalah metode dinamis implisit yang menjadikan instance sebagai argumen pertama.
Sebaliknya, metode statis tidak mengambil contoh sebagai argumen pertama, sehingga disebut 'statis' .
Metode statis memang merupakan fungsi normal yang sama dengan yang di luar definisi kelas.
Untungnya dikelompokkan ke dalam kelas hanya untuk berdiri lebih dekat di mana ia diterapkan, atau Anda mungkin menggulirkan untuk menemukannya.
Saya pikir memberikan versi Python murni staticmethod
dan classmethod
akan membantu untuk memahami perbedaan di antara mereka di tingkat bahasa.
Keduanya adalah deskriptor non-data (Akan lebih mudah untuk memahaminya jika Anda terbiasa dengan deskriptor terlebih dahulu).
class StaticMethod(object):
"Emulate PyStaticMethod_Type() in Objects/funcobject.c"
def __init__(self, f):
self.f = f
def __get__(self, obj, objtype=None):
return self.f
class ClassMethod(object):
"Emulate PyClassMethod_Type() in Objects/funcobject.c"
def __init__(self, f):
self.f = f
def __get__(self, obj, cls=None):
def inner(*args, **kwargs):
if cls is None:
cls = type(obj)
return self.f(cls, *args, **kwargs)
return inner
staticmethod tidak memiliki akses ke attibutes objek, kelas, atau kelas induk dalam hierarki warisan. Itu dapat dipanggil di kelas secara langsung (tanpa membuat objek).
classmethod tidak memiliki akses ke atribut objek. Namun itu dapat mengakses atribut dari kelas dan kelas induk di hierarki warisan. Itu dapat dipanggil di kelas secara langsung (tanpa membuat objek). Jika dipanggil pada objek maka itu sama dengan metode normal yang tidak mengakses self.<attribute(s)>
dan mengakses self.__class__.<attribute(s)>
saja.
Pikir kita memiliki kelas dengan b=2
, kita akan membuat objek dan mengatur ulang ini b=4
di dalamnya. Metode statis tidak dapat mengakses apa pun dari sebelumnya. Metodemetode .b==2
hanya dapat mengakses , melalui cls.b
. Metode normal dapat mengakses keduanya: .b==4
via self.b
dan .b==2
via self.__class__.b
.
Kita dapat mengikuti gaya KISS (tetap sederhana, bodoh): Jangan gunakan metode statis dan metode kelas, jangan gunakan kelas tanpa membuat instance mereka, hanya mengakses atribut objek self.attribute(s)
. Ada bahasa di mana OOP diimplementasikan seperti itu dan saya pikir itu bukan ide yang buruk. :)
Peretasan cepat metode identik lainnya di iPython mengungkapkan bahwa @staticmethod
menghasilkan keuntungan kinerja marjinal (dalam nanodetik), tetapi sebaliknya tampaknya tidak berfungsi. Selain itu, setiap peningkatan kinerja mungkin akan terhapus oleh pekerjaan tambahan memproses metode melalui staticmethod()
saat kompilasi (yang terjadi sebelum eksekusi kode ketika Anda menjalankan skrip).
Demi keterbacaan kode saya akan menghindari @staticmethod
kecuali metode Anda akan digunakan untuk banyak pekerjaan, di mana nanodetik dihitung.