Çağıran arasında herhangi bir fark var mı len([1,2,3])yoksa [1,2,3].__len__()?
Görünür bir fark yoksa perde arkasında farklı olarak ne yapılır?
Yanıtlar:
lenbir koleksiyonun uzunluğunu elde etmek için bir işlevdir. Bir nesnenin __len__yöntemini çağırarak çalışır . __something__nitelikler özeldir ve genellikle göründüğünden daha fazladır ve genellikle doğrudan çağrılmamalıdır.
Uzun zaman önce bir noktada, bir şeyin uzunluğunun bir yöntem kodu değil, bir işlev olması gerektiğine karar verildi, bunun len(a)anlamı yeni başlayanlar için açık olacak, ancak a.len()bu kadar net olmayacaktı. Python başladığında __len__bile yoktu ve lenbirkaç tür nesneyle çalışan özel bir şeydi. Bunun bize bıraktığı durum tamamen mantıklı olsun, burada kalmaktır.
Bir yerleşik veya operatörün "tipik" davranışı __whatever__, ilgili nesneler üzerinde (farklı ve daha hoş sözdizimi ile) uygun sihirli yöntemleri (benzer adlara sahip olanlar) çağırmaktır . Çoğu zaman yerleşik veya operatörün "katma değeri" vardır (ilgili nesnelere bağlı olarak farklı yollar izleyebilir) - lenvs durumunda __len__, yerleşik üzerinde eksik olan sadece biraz akıl sağlığı kontrolüdür. sihirli yöntem:
>>> 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
Yerleşik olarak bir çağrı gördüğünüzde , program bir istisna oluşturmak yerine bundan sonra devam ederse, çağrının negatif olmayan ve 2 ** 31'den küçük bir tamsayı döndürdüğünden eminlen olursunuz - ne zaman bir çağrı görürseniz , kesin olarak emin değilsiniz (kodun yazarının ya Python'a aşina olmaması ya da hiç iyi olmaması ;-).xxx.__len__()
Diğer yerleşik öğeler, basit güvenilirlik kontrollerinin ve okunabilirliğin ötesinde daha fazla katma değer sağlar. Programcılar, tüm Python'u yerleşik çağrılarla ve operatörlerin kullanımıyla çalışacak şekilde tek tip bir şekilde tasarlayarak, asla sihirli yöntemlere çağrı yapmadan, programcılar hangi durumun hangisi olduğunu hatırlama yükünden kurtulmuş olurlar. (Bazen bir hata ortaya çıkar: 2.5'e kadar aramak zorundaydınız foo.next()- 2.6'da, bu hala geriye dönük uyumluluk için çalışsa da, çağırmalısınız next(foo)ve içinde 3.*sihirli yöntem __next__"oops-ey" yerine doğru şekilde adlandırılır next! - ).
Yani genel kural, bunu tam olarak neden yapmanız gerektiğini bilmediğiniz sürece (örneğin, bir alt sınıfta böyle bir yöntemi geçersiz kılarken, eğer alt sınıfın sihirli yönteme açık çağrı yoluyla yapılması gereken üst sınıfa ertelemesi gerekir).
def len(x): return "I am a string." print(len(42)) print(len([1,2,3]))ve I am stringiki kez basıldı . Biraz daha açıklayabilir misin?
__len__özel yöntem (işlev değil) çağıran yerleşik len hakkında konuştu .
lenAynı ada sahip başka bir işlevi değil ( örneğimdeki gibi) yerleşik işlevi çağırdığımdan nasıl emin olabilirim - len. "Yerleşik len fonksiyonunu yeniden tanımlıyorsunuz" veya buna benzer bir uyarı yok. Bence Alex'in cevabında ne söylediğinden emin olamıyorum.
len in vars(__builtins__).values().
Len () 'nin kabaca eşdeğer olduğunu düşünebilirsiniz:
def len(x):
return x.__len__()
Bir avantajı, aşağıdaki gibi şeyler yazmanıza olanak vermesidir:
somelist = [[1], [2, 3], [4, 5, 6]]
map(len, somelist)
onun yerine
map(list.__len__, somelist)
veya
map(operator.methodcaller('__len__'), somelist)
Yine de biraz farklı davranış var. Örneğin, ints durumunda
>>> (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.methodcalleryerine demek istediğini varsayıyorum operator.attrgetter.
Pythond belgelerini kontrol edebilirsiniz :
>>> 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