Len () ve .__ len __ () arasındaki fark nedir?


Yanıtlar:


103

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.


67

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).


Ben yeni başlayan Python kullanıcısıyım (başlangıç ​​seviyesindeki programcı düşünmedi) ve "dahili len çağrısı gördüğünüzde, programın bir istisna oluşturmak yerine bundan sonra devam edeceğinden emin olabilirsiniz". Bunu denedim 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?
Darek Nędza

4
@ DarekNędza Bunun yerleşik len ile ilgili olan yukarıdakilerle hiçbir ilgisi yok. Sadece len işlevinizi tanımladınız, bu elbette istediğiniz her şeyi döndürebilir. OP, söz konusu nesnede __len__özel yöntem (işlev değil) çağıran yerleşik len hakkında konuştu .
Veky

@Veky 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.
Darek Nędza

3
Alex açıkça söyledi eğer sen yerleşiğini aradığınız, sonra sen ..._ eminsin. Yerleşik aradığınızdan emin olmak konusunda hiçbir şey söylemedi. Bunu biliyor etmek istiyorsan, şunları yapabilirsiniz: len in vars(__builtins__).values().
Veky

1
Ne yazık ki, bu Python'daki nesneler için ortak bir temel sınıfın olmamasına başka bir örnek. Sözdizimsel bağlam değiştirme her zaman çılgınca olmuştur. Bazı durumlarda altçizgi yöntemini kullanmak yaygın bir deyimdir, diğerlerinde ise birçok nesnede ortak olan bir şeyi yapmak için işlev gibi bir şey kullanılmalıdır. Aynı zamanda garip çünkü birçok nesnenin len için anlamsal kullanımı yoktur. Bazen nesne modeli daha çok C ++ gibi, mutfak kokulu ..
uchuugaka

28

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()

2
Onun operator.methodcalleryerine demek istediğini varsayıyorum operator.attrgetter.
Elazar

5

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
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.