Apa perbedaan antara fungsi yang didekorasi dengan yang @staticmethod
didekorasi @classmethod
?
python
oop
methods
python-decorators
Daryl Spitzer
sumber
sumber
Jawaban:
Mungkin sedikit contoh kode akan membantu: Perhatikan perbedaan tanda tangan panggilan
foo
,class_foo
danstatic_foo
:Di bawah ini adalah cara biasa instance instance memanggil metode. Contoh objek,,
a
secara implisit disahkan sebagai argumen pertama.Dengan classmethods , kelas instance objek secara implisit dilewatkan sebagai argumen pertama alih-alih
self
.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, tetapiA.class_foo(1)
berfungsi dengan baik:Satu kegunaan yang ditemukan orang untuk metode kelas adalah membuat konstruktor alternatif yang dapat diwariskan .
Dengan metode statis , baik
self
(objek contoh) maupuncls
(kelas) secara implisit dilewatkan sebagai argumen pertama. Mereka berperilaku seperti fungsi sederhana kecuali bahwa Anda dapat memanggil mereka dari instance atau kelas:Metode statis digunakan untuk mengelompokkan fungsi yang memiliki beberapa koneksi logis dengan kelas ke kelas.
foo
hanya sebuah fungsi, tetapi ketika Anda menelepona.foo
Anda tidak hanya mendapatkan fungsi, Anda mendapatkan versi "sebagian diterapkan" dari fungsi dengan instance instance objeka
terikat sebagai argumen pertama ke fungsi.foo
mengharapkan 2 argumen, sementaraa.foo
hanya mengharapkan 1 argumen.a
terikatfoo
. Itulah yang dimaksud dengan istilah "terikat" di bawah:Dengan
a.class_foo
,a
tidak terikatclass_foo
, melainkan kelasA
terikatclass_foo
.Di sini, dengan metode statis, meskipun metode,
a.static_foo
hanya mengembalikan fungsi yang baik tanpa argumen terikat.static_foo
mengharapkan 1 argumen, dana.static_foo
mengharapkan 1 argumen juga.Dan tentu saja hal yang sama terjadi ketika Anda menelepon
static_foo
dengan kelasA
sebagai gantinya.sumber
@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 menggunakanexecute
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:sumber
Pada dasarnya
@classmethod
membuat metode yang argumen pertamanya adalah kelas dari mana (bukan dari instance kelas),@staticmethod
tidak memiliki argumen implisit.sumber
Dokumen python resmi:
@classmethod
@staticmethod
sumber
Berikut adalah artikel singkat tentang pertanyaan ini
sumber
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.
sumber
cls._counter
masih akan menjadicls._counter
bahkan jika kode tersebut diletakkan di kelas yang berbeda, atau nama kelas diubah.Apple._counter
khusus untukApple
kelas; untuk kelas yang berbeda, atau ketika nama kelas diubah, Anda perlu mengubah kelas yang direferensikan.Anda mungkin telah melihat kode Python seperti pseudocode ini, yang menunjukkan tanda tangan dari berbagai jenis metode dan menyediakan docstring untuk menjelaskan masing-masing:
Metode Instance Normal
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']
:Metode terikat
Metode instan dapat diikat melalui pencarian bertitik untuk digunakan nanti.
Misalnya, ini mengikat
str.join
metode ke':'
instance: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:
Metode Statis
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 daristring
modul dengan Python 3. Itu membuat tabel terjemahan cocok untuk dikonsumsi olehstr.translate
. Tampaknya agak konyol ketika digunakan dari instance string, seperti yang ditunjukkan di bawah ini, tetapi mengimpor fungsi daristring
modul agak canggung, dan senang bisa menyebutnya dari kelas, seperti padastr.maketrans
Dalam python 2, Anda harus mengimpor fungsi ini dari modul string yang semakin tidak berguna:
Metode Kelas
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.)Ketika kita subclass dict, kita dapat menggunakan konstruktor yang sama, yang membuat turunan dari subclass.
Lihat kode sumber panda untuk contoh serupa lainnya dari konstruktor alternatif, dan lihat juga dokumentasi Python resmi pada
classmethod
danstaticmethod
.sumber
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 iniMari kita anggap kita memiliki
Person
kelas yang membutuhkan dua argumenfirst_name
danlast_name
dan menciptakan instance dariPerson
.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).
Namun, Anda dapat mencapai hal yang sama menggunakan
@classmethod
seperti yang disebutkan di bawah iniMetode 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.dan Anda cukup menelepon menggunakan
class name
sumber
def __init__(self, first_name, last_name="")
bukan metode kelasget_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.
sumber
@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:
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.sumber
Metode Statis:
Manfaat Metode Statis:
Lebih nyaman untuk mengimpor versus fungsi tingkat modul karena setiap metode tidak harus diimpor secara khusus
Metode Kelas:
Ini dibuat dengan classmethod in-built function.
sumber
@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:Sebenarnya,
classmethod
memiliki overhead runtime tetapi memungkinkan untuk mengakses kelas pemilik. Atau saya sarankan menggunakan metaclass dan meletakkan metode kelas pada metaclass itu:sumber
c = C(); c.foo()
memunculkan AttributeError, yang harus Anda lakukantype(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).sumber
Hanya argumen pertama yang berbeda :
Lebih detail ...
metode normal
Ketika metode objek dipanggil, ia secara otomatis diberikan argumen tambahan
self
sebagai argumen pertamanya. Yaitu, metodeharus dipanggil dengan 2 argumen.
self
secara otomatis berlalu, dan itu adalah objek itu sendiri .metode kelas
Ketika metode tersebut didekorasi
argumen yang disediakan secara otomatis bukan
self
, tetapi kelasself
.metode statis
Ketika metode tersebut didekorasi
metode ini tidak diberikan argumen otomatis sama sekali. Hanya diberikan parameter yang dipanggil dengan.
penggunaan
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, sepertiMath
metode statis kelas Java )sumber
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.
sumber
Pertimbangan lain sehubungan dengan staticmethod vs classmethod muncul dengan warisan. Katakanlah Anda memiliki kelas berikut:
Dan Anda kemudian ingin menimpa
bar()
di kelas anak:Ini berfungsi, tetapi perhatikan bahwa sekarang
bar()
implementasi di kelas anak (Foo2
) tidak dapat lagi memanfaatkan apa pun yang spesifik untuk kelas itu. Misalnya, katakanFoo2
memiliki metode yang disebutmagic()
yang ingin Anda gunakan dalamFoo2
implementasibar()
:Solusi di sini akan memanggil
Foo2.magic()
dibar()
, tapi kemudian Anda mengulangi diri sendiri (jika namaFoo2
perubahan, Anda harus ingat untuk memperbarui bahwabar()
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). Jikabar()
aclassmethod
kita akan baik-baik saja:Memberi:
In Foo2 MAGIC
sumber
Saya akan mencoba menjelaskan perbedaan dasar menggunakan contoh.
1 - kita dapat langsung memanggil metode statis dan metode tanpa menginisialisasi
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.
sumber
@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
sumber
Anda mungkin ingin mempertimbangkan perbedaan antara:
dan
Ini telah berubah antara python2 dan python3:
python2:
python3:
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
sumber
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!
sumber
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.sumber
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.
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.
sumber
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.
sumber
Saya pikir memberikan versi Python murni
staticmethod
danclassmethod
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).
sumber
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 mengaksesself.__class__.<attribute(s)>
saja.Pikir kita memiliki kelas dengan
b=2
, kita akan membuat objek dan mengatur ulang inib=4
di dalamnya. Metode statis tidak dapat mengakses apa pun dari sebelumnya. Metodemetode.b==2
hanya dapat mengakses , melaluicls.b
. Metode normal dapat mengakses keduanya:.b==4
viaself.b
dan.b==2
viaself.__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. :)sumber
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 melaluistaticmethod()
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.sumber