Saya telah bermain-main dengan Python baru-baru ini, dan satu hal yang menurut saya agak aneh adalah penggunaan ekstensif 'metode ajaib', misalnya untuk membuat panjangnya tersedia, sebuah objek menerapkan metode def __len__(self)
, dan kemudian dipanggil ketika Anda menulis len(obj)
.
Saya hanya bertanya-tanya mengapa objek tidak hanya mendefinisikan len(self)
metode dan memanggilnya langsung sebagai anggota objek, misalnya obj.len()
? Saya yakin pasti ada alasan bagus untuk Python melakukan seperti itu, tetapi sebagai pemula saya belum mengetahui apa itu.
python
magic-methods
Greg Beech
sumber
sumber
len()
ataureversed()
berlaku untuk banyak jenis objek, tetapi metode sepertiappend()
hanya berlaku untuk urutan, dll.Jawaban:
AFAIK,
len
istimewa dalam hal ini dan memiliki akar sejarah.Berikut kutipan dari FAQ :
"Metode magis" lainnya (sebenarnya disebut metode khusus dalam cerita rakyat Python) sangat masuk akal, dan fungsi serupa ada di bahasa lain. Mereka kebanyakan digunakan untuk kode yang dipanggil secara implisit ketika sintaks khusus digunakan.
Sebagai contoh:
dan seterusnya...
sumber
Dari Zen of Python:
Ini adalah salah satu alasan - dengan metode kustom, pengembang akan bebas untuk memilih nama metode yang berbeda, seperti
getLength()
,length()
,getlength()
atau apapun. Python memberlakukan penamaan yang ketat sehingga fungsi umumlen()
dapat digunakan.Semua operasi yang umum untuk banyak jenis objek dimasukkan ke dalam metode ajaib, seperti
__nonzero__
,__len__
atau__repr__
. Namun, sebagian besar bersifat opsional.Overloading operator juga dilakukan dengan metode ajaib (misalnya
__le__
), jadi masuk akal untuk menggunakannya juga untuk operasi umum lainnya.sumber
Python menggunakan kata "metode ajaib" , karena metode tersebut benar-benar melakukan sihir untuk program Anda. Salah satu keuntungan terbesar menggunakan metode sihir Python adalah bahwa metode ini menyediakan cara sederhana untuk membuat objek berperilaku seperti tipe bawaan. Itu berarti Anda dapat menghindari cara-cara yang buruk, kontra-intuitif, dan tidak standar dalam melakukan operator dasar.
Pertimbangkan contoh berikut:
Ini memberikan kesalahan, karena jenis kamus tidak mendukung penambahan. Sekarang, mari perluas kelas kamus dan tambahkan metode ajaib "__add__" :
Sekarang, ini memberikan hasil sebagai berikut.
Jadi, dengan menambahkan metode ini, tiba-tiba keajaiban telah terjadi dan kesalahan yang Anda dapatkan sebelumnya, telah hilang.
Saya harap, ini membuat semuanya jelas bagi Anda. Untuk informasi lebih lanjut, lihat:
Panduan Metode Sulap Python (Rafe Kettler, 2012)
sumber
Beberapa fungsi ini melakukan lebih dari satu metode yang dapat diimplementasikan (tanpa metode abstrak pada superclass). Misalnya
bool()
tindakan seperti ini:Anda juga bisa 100% yakin bahwa
bool()
akan selalu mengembalikan True atau False; jika Anda mengandalkan suatu metode, Anda tidak bisa sepenuhnya yakin apa yang akan Anda dapatkan.Beberapa fungsi lain yang memiliki implementasi yang relatif rumit (lebih rumit daripada metode sihir yang mendasari kemungkinan besar) adalah
iter()
dancmp()
, dan semua metode atribut (getattr
,setattr
dandelattr
). Hal-hal sepertiint
juga mengakses metode sihir saat melakukan pemaksaan (Anda dapat menerapkan__int__
), tetapi melakukan tugas ganda sebagai tipe.len(obj)
sebenarnya adalah satu kasus yang menurut saya tidak pernah berbedaobj.__len__()
.sumber
hasattr()
saya akan menggunakantry:
/except AttributeError:
dan alih-alihif obj.__len__(): return True else: return False
saya hanya akan mengatakanreturn obj.__len__() > 0
tetapi itu hanya hal-hal gaya.bool(x)
dirujuk btwx.__nonzero__()
), metode Anda tidak akan berfungsi. Instance bool memiliki metode__nonzero__()
, dan kode Anda akan terus memanggil dirinya sendiri begitu obj menjadi bool. Mungkinbool(obj.__bool__())
harus diperlakukan sama dengan Anda__len__
? (Atau apakah kode ini benar-benar berfungsi untuk Python 3?)len(x)
danx.__len__()
adalah bahwa yang pertama akan memunculkan OverflowError untuk panjang yang melebihisys.maxsize
, sedangkan yang terakhir umumnya tidak untuk jenis yang diimplementasikan dengan Python. Itu lebih merupakan bug daripada fitur, meskipun (misalnya objek jangkauan Python 3.2 sebagian besar dapat menangani rentang besar yang sewenang-wenang, tetapi menggunakannyalen
dengan mereka mungkin gagal. Namun__len__
gagal juga, karena mereka diterapkan di C daripada Python)Mereka sebenarnya bukan "nama ajaib". Ini hanyalah antarmuka yang harus diterapkan objek untuk menyediakan layanan tertentu. Dalam pengertian ini, mereka tidak lebih ajaib daripada definisi antarmuka yang telah ditentukan sebelumnya yang harus Anda implementasikan ulang.
sumber
Meskipun alasannya sebagian besar bersifat historis, ada beberapa keanehan dalam Python
len
yang menggunakan fungsi alih-alih metode yang sesuai.Beberapa operasi di Python diimplementasikan sebagai metode, misalnya
list.index
dandict.append
, sementara yang lain diimplementasikan sebagai callable dan metode ajaib, misalnyastr
daniter
danreversed
. Kedua kelompok tersebut cukup berbeda sehingga pendekatan yang berbeda dapat dibenarkan:str
,int
dan teman adalah tipe. Lebih masuk akal untuk memanggil konstruktor.iter
mungkin memanggil__getitem__
jika__iter__
tidak tersedia, dan mendukung argumen tambahan yang tidak cocok dalam panggilan metode. Untuk alasan yang samait.next()
telah diubah menjadinext(it)
dalam versi terbaru Python - itu lebih masuk akal.__iter__
dan__next__
- itu disebutfor
loop. Untuk konsistensi, suatu fungsi lebih baik. Dan itu membuatnya lebih baik untuk pengoptimalan tertentu.repr
bertindak sepertistr
itu. Memilikistr(x)
versusx.repr()
akan membingungkan.isinstance
.getattr(x, 'a')
merupakan cara lain untuk melakukanx.a
dangetattr
berbagi banyak kualitas yang disebutkan di atas.Saya pribadi menyebut metode grup pertama dan grup kedua seperti operator. Ini bukan perbedaan yang sangat bagus, tapi saya harap ini bisa membantu.
Karena itu,
len
tidak sepenuhnya cocok dengan kelompok kedua. Ini lebih dekat dengan operasi di yang pertama, dengan satu-satunya perbedaan bahwa itu jauh lebih umum daripada hampir semua dari mereka. Tapi satu-satunya hal yang dilakukannya adalah menelepon__len__
, dan itu sangat dekatL.index
. Namun, ada beberapa perbedaan. Misalnya,__len__
mungkin dipanggil untuk implementasi fitur lain, sepertibool
, jika metode dipanggil,len
Anda mungkin memutuskanbool(x)
dengan kustomlen
metode yang melakukan hal yang sangat berbeda.Singkatnya, Anda memiliki sekumpulan fitur yang sangat umum yang mungkin diterapkan kelas yang dapat diakses melalui operator, melalui fungsi khusus (yang biasanya melakukan lebih dari sekadar implementasi, seperti yang dilakukan operator), selama konstruksi objek, dan semuanya berbagi beberapa ciri umum. Sisanya adalah metode. Dan
len
merupakan pengecualian dari aturan itu.sumber
Tidak banyak yang bisa ditambahkan ke dua tulisan di atas, tapi semua fungsi "ajaib" sebenarnya tidak ajaib sama sekali. Mereka adalah bagian dari modul __ builtins__ yang secara implisit / otomatis diimpor ketika interpreter dimulai. Yaitu:
terjadi setiap kali sebelum program Anda dimulai.
Saya selalu berpikir akan lebih benar jika Python hanya melakukan ini untuk shell interaktif, dan membutuhkan skrip untuk mengimpor berbagai bagian dari bawaan yang mereka butuhkan. Penanganan __ main__ yang mungkin berbeda juga akan bagus di shell vs interaktif. Bagaimanapun, periksa semua fungsinya, dan lihat bagaimana rasanya tanpanya:
sumber