Apa perbedaan antara metode kelas berikut?
Apakah yang satu itu statis dan yang lain tidak?
class Test(object):
def method_one(self):
print "Called method_one"
def method_two():
print "Called method_two"
a_test = Test()
a_test.method_one()
a_test.method_two()
@classmethod
definisi. Parameter pertama harus dipanggilcls
alih-alihself
dan akan menerima objek kelas daripada instance kelas Anda:Test.method_three()
dana_test.method_three()
setara.self
argumen? Apakah ada kasus penggunaan yang kuat untuk ini?Jawaban:
Dalam Python, ada perbedaan antara terikat dan terikat metode.
Pada dasarnya, panggilan ke fungsi anggota (seperti
method_one
), fungsi terikatditerjemahkan ke
yaitu panggilan ke metode tidak terikat. Karena itu, panggilan ke versi Anda
method_two
akan gagal dengan aTypeError
Anda dapat mengubah perilaku metode menggunakan dekorator
Dekorator memberi tahu metaclass bawaan bawaan
type
(kelas kelas, lih. Pertanyaan ini ) untuk tidak membuat metode terikatmethod_two
.Sekarang, Anda dapat memanggil metode statis baik secara instan atau di kelas secara langsung:
sumber
Metode dengan Python adalah hal yang sangat, sangat sederhana setelah Anda memahami dasar-dasar sistem deskriptor. Bayangkan kelas berikut:
Sekarang mari kita lihat kelas itu di shell:
Seperti yang Anda lihat jika Anda mengakses
foo
atribut di kelas Anda mendapatkan kembali metode yang tidak terikat, namun di dalam penyimpanan kelas (dict) ada fungsi. Kenapa begitu? Alasan untuk ini adalah bahwa kelas kelas Anda mengimplementasikan a__getattribute__
yang menyelesaikan deskriptor. Kedengarannya rumit, tetapi tidak.C.foo
kira-kira setara dengan kode ini dalam kasus khusus:Itu karena fungsi memiliki
__get__
metode yang membuat mereka deskriptor. Jika Anda memiliki instance kelas hampir sama, hanya ituNone
adalah instance kelas:Sekarang mengapa Python melakukan itu? Karena objek metode mengikat parameter pertama dari suatu fungsi ke turunan kelas. Dari situlah datangnya diri. Sekarang kadang-kadang Anda tidak ingin kelas Anda membuat fungsi sebagai metode, di situlah
staticmethod
ikut bermain:The
staticmethod
dekorator membungkus kelas Anda dan alat dummy__get__
yang mengembalikan fungsi dibungkus sebagai fungsi dan bukan sebagai metode:Harapan itu menjelaskannya.
sumber
staticmethod
dekorator membungkus kelas Anda (...) Frasa ini adalah sedikit menyesatkan sebagai kelas yang sedang dibungkus adalah kelas dari metodefoo
dan bukan kelas di manafoo
didefinisikan.Saat Anda memanggil anggota kelas, Python secara otomatis menggunakan referensi ke objek sebagai parameter pertama. Variabel
self
sebenarnya tidak berarti apa-apa, itu hanya konvensi pengkodean. Anda bisa menyebutnyagargaloo
jika Anda mau. Yang mengatakan, panggilan untukmethod_two
akan menaikkanTypeError
, karena Python secara otomatis mencoba untuk melewatkan parameter (referensi ke objek induknya) ke metode yang didefinisikan sebagai tidak memiliki parameter.Untuk benar-benar membuatnya berfungsi, Anda bisa menambahkan ini ke definisi kelas Anda:
atau Anda bisa menggunakan
@staticmethod
fungsi dekorator .sumber
sumber
Class.instance_method() # The class cannot use an instance method
itu bisa digunakan. Cukup berikan contoh secara manual:Class.instance_method(a)
TyeError
garis.a.class_method()
, tampaknyaa.c
sudah diperbarui1
, jadi panggilanClass.class_method()
, memperbaruiClass.c
variabel ke2
. Namun, ketika Anda ditugaskana.c=5
, mengapaClass.c
tidak diperbarui5
?method_two tidak akan berfungsi karena Anda mendefinisikan fungsi anggota tetapi tidak memberi tahu apa fungsi anggota tersebut. Jika Anda mengeksekusi baris terakhir Anda akan mendapatkan:
Jika Anda mendefinisikan fungsi anggota untuk suatu kelas, argumen pertama harus selalu 'mandiri'.
sumber
Penjelasan yang akurat dari Armin Ronacher di atas, memperluas jawabannya sehingga pemula seperti saya memahaminya dengan baik:
Perbedaan dalam metode yang didefinisikan dalam suatu kelas, apakah metode statis atau contoh (masih ada jenis lain - metode kelas - tidak dibahas di sini sehingga melewatkannya), terletak pada fakta apakah mereka entah bagaimana terikat pada instance kelas atau tidak. Sebagai contoh, katakan apakah metode menerima referensi ke instance kelas selama runtime
The
__dict__
properti kamus dari objek kelas memegang referensi untuk semua properti dan metode dari objek kelas dan dengan demikianmetode foo dapat diakses seperti di atas. Poin penting yang perlu diperhatikan di sini adalah bahwa segala sesuatu di python adalah objek dan referensi dalam kamus di atas sendiri menunjuk ke objek lain. Izinkan saya menyebutnya Objek Properti Kelas - atau sebagai CPO dalam lingkup jawaban saya untuk singkatnya.
Jika CPO adalah descriptor, maka python interpretor memanggil
__get__()
metode CPO untuk mengakses nilai yang dikandungnya.Untuk menentukan apakah CPO adalah deskriptor, penafsir python memeriksa jika mengimplementasikan protokol deskriptor. Untuk mengimplementasikan protokol deskriptor adalah dengan mengimplementasikan 3 metode
untuk mis
dimana
self
adalah CPO (bisa berupa instance dari daftar, str, fungsi dll) dan disediakan oleh runtimeinstance
adalah turunan dari kelas di mana CPO ini didefinisikan (objek 'c' di atas) dan perlu kejelasan yang disediakan oleh kamiowner
adalah kelas di mana CPO ini didefinisikan (objek kelas 'C' di atas) dan perlu disediakan oleh kami. Namun ini karena kami menyebutnya di CPO. ketika kita menyebutnya sebagai instance, kita tidak perlu menyediakan ini karena runtime dapat menyediakan instance atau kelasnya (polimorfisme)value
adalah nilai yang dimaksudkan untuk CPO dan perlu dipasok oleh kamiTidak semua CPO adalah deskriptor. Sebagai contoh
Ini karena kelas daftar tidak mengimplementasikan protokol deskriptor.
Jadi argumen sendiri
c.foo(self)
diperlukan karena tanda tangan metodenya sebenarnya iniC.__dict__['foo'].__get__(c, C)
(seperti yang dijelaskan di atas, C tidak diperlukan karena dapat ditemukan atau polymorphed) Dan ini juga mengapa Anda mendapatkan TypeError jika Anda tidak memberikan argumen contoh yang diperlukan.Jika Anda perhatikan metode ini masih direferensikan melalui kelas Object C dan pengikatan dengan instance kelas dicapai melalui melewati konteks dalam bentuk objek instance ke dalam fungsi ini.
Ini cukup luar biasa karena jika Anda memilih untuk tidak menyimpan konteks atau tidak mengikat pada instance, yang diperlukan hanyalah menulis kelas untuk membungkus deskriptor CPO dan mengganti
__get__()
metodenya sehingga tidak memerlukan konteks. Kelas baru ini adalah apa yang kita sebut dekorator dan diterapkan melalui kata kunci@staticmethod
Tidak adanya konteks dalam CPO yang dibungkus baru
foo
tidak menimbulkan kesalahan dan dapat diverifikasi sebagai berikut:Use case dari metode statis lebih merupakan penamaan namespace dan kode rawat (mengeluarkannya dari kelas dan membuatnya tersedia di seluruh modul dll).
Mungkin lebih baik untuk menulis metode statis daripada metode contoh bila memungkinkan, kecuali tentu saja Anda perlu membuat kontekstual metode (seperti variabel akses contoh, variabel kelas dll). Salah satu alasannya adalah untuk memudahkan pengumpulan sampah dengan tidak menyimpan referensi yang tidak diinginkan ke objek.
sumber
itu adalah kesalahan.
pertama-tama, baris pertama harus seperti ini (hati-hati dengan modal)
Setiap kali Anda memanggil metode kelas, itu mendapatkan dirinya sebagai argumen pertama (maka nama diri) dan method_two memberikan kesalahan ini
sumber
Yang kedua tidak akan berfungsi karena ketika Anda memanggilnya seperti itu python secara internal mencoba menyebutnya dengan contoh a_test sebagai argumen pertama, tetapi method_two Anda tidak menerima argumen apa pun, jadi itu tidak akan berfungsi, Anda akan mendapatkan runtime kesalahan. Jika Anda ingin yang setara dengan metode statis, Anda dapat menggunakan metode kelas. Ada jauh lebih sedikit kebutuhan untuk metode kelas dalam Python daripada metode statis dalam bahasa seperti Java atau C #. Paling sering solusi terbaik adalah dengan menggunakan metode dalam modul, di luar definisi kelas, mereka bekerja lebih efisien daripada metode kelas.
sumber
Class Test(object): @staticmethod def method_two(): print(“called method_two”)
Satu kasus penggunaan, yang saya pikirkan adalah ketika Anda ingin fungsi menjadi bagian dari kelas, tetapi tidak ingin pengguna mengakses fungsi secara langsung. Jadimethod_two
bisa dipanggil oleh fungsi lain di dalamTest
instance, tetapi tidak bisa disebut menggunakana_test.method_two()
. Jika saya menggunakandef method_two()
, apakah ini akan berfungsi untuk kasus penggunaan ini? Atau adakah cara yang lebih baik untuk memodifikasi definisi fungsi, sehingga berfungsi seperti yang dimaksudkan untuk use case di atas?Panggilan ke method_two akan mengeluarkan pengecualian untuk tidak menerima parameter sendiri runtime Python akan secara otomatis melewatinya.
Jika Anda ingin membuat metode statis di kelas Python, hiasi dengan
staticmethod decorator
.sumber
Silakan baca dokumen ini dari Guido First Class, semuanya dengan jelas menjelaskan bagaimana metode Unbound, Bound dilahirkan.
sumber
Definisi
method_two
tidak valid. Saat Anda meneleponmethod_two
, Anda akan dapatkanTypeError: method_two() takes 0 positional arguments but 1 was given
dari penerjemah.Metode instance adalah fungsi yang dibatasi ketika Anda menyebutnya suka
a_test.method_two()
. Secara otomatis menerimaself
, yang menunjuk ke instanceTest
, sebagai parameter pertama. Melaluiself
parameter, metode instance dapat dengan bebas mengakses atribut dan memodifikasinya pada objek yang sama.sumber
Metode Tidak Terbatas
Metode tidak terikat adalah metode yang belum terikat ke instance kelas tertentu.
Metode Terikat
Metode Bound adalah metode yang terikat pada instance kelas tertentu.
Seperti yang didokumentasikan di sini , diri dapat merujuk pada hal-hal yang berbeda tergantung pada fungsi yang terikat, tidak terikat atau statis.
Lihatlah contoh berikut:
Karena kami tidak menggunakan instance kelas -
obj
- pada panggilan terakhir, kita dapat mengatakan itu terlihat seperti metode statis.Jika demikian, apa perbedaan antara
MyClass.some_method(10)
panggilan dan panggilan ke fungsi statis yang dihiasi dengan a@staticmethod
dekorator?Dengan menggunakan dekorator, kami secara eksplisit memperjelas bahwa metode tersebut akan digunakan tanpa membuat instance terlebih dahulu. Biasanya seseorang tidak akan mengharapkan metode anggota kelas untuk digunakan tanpa instance dan mengaksesnya dapat menyebabkan kesalahan yang mungkin tergantung pada struktur metode.
Juga, dengan menambahkan
@staticmethod
dekorator, kami memungkinkan untuk dijangkau melalui objek juga.Anda tidak dapat melakukan contoh di atas dengan metode instance. Anda mungkin selamat dari yang pertama (seperti yang kami lakukan sebelumnya) tetapi yang kedua akan diterjemahkan ke dalam panggilan tidak terikat
MyClass.some_method(obj, 10)
yang akan memunculkanTypeError
karena metode instance mengambil satu argumen dan Anda tidak sengaja mencoba untuk melewati dua.Kemudian, Anda mungkin berkata, "jika saya bisa memanggil metode statis baik melalui instance dan kelas,
MyClass.some_static_method
danMyClass().some_static_method
harus metode yang sama." Iya!sumber
Metode terikat = metode instance
Metode tidak terikat = metode statis.
sumber