Apakah ada perbedaan antara menelepon len([1,2,3])atau [1,2,3].__len__()?
Jika tidak ada perbedaan yang terlihat, apa yang dilakukan secara berbeda di belakang layar?
Jawaban:
lenmerupakan fungsi untuk mendapatkan panjang suatu koleksi. Ia bekerja dengan memanggil __len__metode objek. __something__atribut khusus dan biasanya lebih dari yang terlihat, dan umumnya tidak boleh dipanggil secara langsung.
Telah diputuskan pada suatu saat yang lalu mendapatkan panjang dari sesuatu harus menjadi fungsi dan bukan kode metode, alasan itu len(a)artinya akan jelas bagi pemula tetapi a.len()tidak akan sejelas. Ketika Python dimulai __len__bahkan tidak ada dan lenmerupakan hal khusus yang bekerja dengan beberapa jenis objek. Apakah situasi ini membuat kita benar-benar masuk akal atau tidak, itu akan tetap ada.
Seringkali terjadi bahwa perilaku "khas" dari operator atau bawaan adalah memanggil (dengan sintaks yang berbeda dan lebih bagus) metode ajaib yang sesuai (yang memiliki nama seperti __whatever__) pada objek yang terlibat. Seringkali operator atau bawaan memiliki "nilai tambah" (dapat mengambil jalur yang berbeda bergantung pada objek yang terlibat) - dalam kasus lenvs __len__, itu hanya sedikit pemeriksaan kewarasan pada bawaan yang hilang dari metode ajaib:
>>> class bah(object):
... def __len__(self): return "an inch"
...
>>> bah().__len__()
'an inch'
>>> len(bah())
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'str' object cannot be interpreted as an integer
Saat Anda melihat panggilan ke lenbuilt-in, Anda yakin bahwa, jika program berlanjut setelah itu daripada memunculkan pengecualian, panggilan tersebut mengembalikan integer, non-negatif, dan kurang dari 2 ** 31 - saat Anda melihat panggilan ke xxx.__len__(), Anda tidak memiliki kepastian (kecuali bahwa pembuat kode tidak terbiasa dengan Python atau tidak bagus ;-).
Built-in lainnya memberikan nilai tambah lebih dari sekadar pemeriksaan kewarasan dan keterbacaan. Dengan mendesain secara seragam semua Python untuk bekerja melalui panggilan ke bawaan dan penggunaan operator, tidak pernah melalui panggilan ke metode ajaib, programmer terhindar dari beban mengingat kasus mana yang mana. (Kadang-kadang kesalahan menyelinap di: hingga 2.5, Anda harus memanggil foo.next()- di 2.6, sementara itu masih berfungsi untuk kompatibilitas mundur, Anda harus memanggil next(foo), dan di 3.*, metode ajaib dinamai dengan benar __next__alih-alih "oops-ey" next! - ).
Jadi aturan umumnya adalah jangan pernah memanggil metode ajaib secara langsung (tetapi selalu secara tidak langsung melalui built-in) kecuali Anda tahu persis mengapa Anda perlu melakukan itu (misalnya, ketika Anda mengganti metode seperti itu dalam subkelas, jika subclass harus tunduk pada superclass yang harus dilakukan melalui panggilan eksplisit ke metode ajaib).
def len(x): return "I am a string." print(len(42)) print(len([1,2,3]))dan dicetak I am stringdua kali. Bisakah Anda menjelaskannya lebih lanjut?
__len__ khusus (bukan fungsi) pada objek yang sedang dipertimbangkan.
lenbukan beberapa fungsi lain (seperti dalam contoh saya) yang kebetulan memiliki nama yang sama - len. Tidak ada peringatan seperti "Anda mendefinisikan ulang fungsi built-in len" atau sesuatu seperti ini. Menurut saya, saya tidak bisa memastikan apa yang dikatakan Alex dalam jawabannya.
len in vars(__builtins__).values().
Anda bisa menganggap len () secara kasar setara dengan
def len(x):
return x.__len__()
Salah satu keuntungannya adalah memungkinkan Anda untuk menulis hal-hal seperti
somelist = [[1], [2, 3], [4, 5, 6]]
map(len, somelist)
dari pada
map(list.__len__, somelist)
atau
map(operator.methodcaller('__len__'), somelist)
Ada perilaku yang sedikit berbeda. Misalnya dalam kasus ints
>>> (1).__len__()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'int' object has no attribute '__len__'
>>> len(1)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: object of type 'int' has no len()
operator.methodcallerbukan operator.attrgetter.
Anda dapat memeriksa dokumen Pythond :
>>> class Meta(type):
... def __getattribute__(*args):
... print "Metaclass getattribute invoked"
... return type.__getattribute__(*args)
...
>>> class C(object):
... __metaclass__ = Meta
... def __len__(self):
... return 10
... def __getattribute__(*args):
... print "Class getattribute invoked"
... return object.__getattribute__(*args)
...
>>> c = C()
>>> c.__len__() # Explicit lookup via instance
Class getattribute invoked
10
>>> type(c).__len__(c) # Explicit lookup via type
Metaclass getattribute invoked
10
>>> len(c) # Implicit lookup
10