लेन () और .__ लेन __ () के बीच अंतर?


जवाबों:


102

lenएक संग्रह की लंबाई पाने के लिए एक समारोह है। यह किसी ऑब्जेक्ट की __len__विधि को कॉल करके काम करता है । __something__विशेषताएं विशेष हैं और आमतौर पर आंख से मिलती है, और आम तौर पर सीधे नहीं कहा जाना चाहिए।

यह कुछ समय पहले तय किया गया था कि किसी चीज की लंबाई एक फ़ंक्शन और विधि कोड नहीं होनी चाहिए, यह तर्क देते हुए कि इसका len(a)अर्थ शुरुआती के लिए स्पष्ट a.len()होगा लेकिन उतना स्पष्ट नहीं होगा। जब पायथन शुरू __len__भी नहीं हुआ था और lenएक विशेष चीज थी जो कुछ प्रकार की वस्तुओं के साथ काम करती थी। यह स्थिति हमें छोड़ती है या नहीं, यह समझ में आता है।


66

यह अक्सर ऐसा होता है कि अंतर्निर्मित या ऑपरेटर के "विशिष्ट" व्यवहार में __whatever__शामिल वस्तुओं पर उपयुक्त जादू के तरीकों (जैसे नामों के साथ ) को कॉल करना (अलग और अच्छे सिंटैक्स के साथ ) होता है। अक्सर अंतर्निहित या ऑपरेटर में "अतिरिक्त मूल्य" होता है (यह इसमें शामिल वस्तुओं के आधार पर अलग-अलग पथ लेने में सक्षम होता है) - lenबनाम के मामले में __len__, यह बिल्ट-इन पर थोड़ी सी पवित्रता की जाँच है जो इसमें से गायब है जादू की विधि:

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

जब आप lenबिल्ट-इन में कॉल देखते हैं , तो आपको यकीन है कि, यदि प्रोग्राम इसके बाद भी जारी रहता है, तो अपवाद को बढ़ाने के बजाय, कॉल ने एक पूर्णांक, गैर-ऋणात्मक और 2 ** 31 से कम लौटाया है - जब आपको एक कॉल दिखाई देता है xxx.__len__(), आपको कोई निश्चितता नहीं है (सिवाय इसके कि कोड का लेखक या तो पायथन से अपरिचित है या कोई अच्छा नहीं; ;-)

अन्य बिल्ट-इन सरल संचित जांच और पठनीयता से परे और भी अधिक मूल्य प्रदान करते हैं। बिल्डरों को कॉल करने और ऑपरेटरों के उपयोग के माध्यम से काम करने के लिए अजगर के सभी को समान रूप से डिजाइन करके, जादू के तरीकों के लिए कॉल के माध्यम से, प्रोग्रामर को यह याद रखने के बोझ से बख्शा नहीं जाता है कि कौन सा मामला है। (कभी-कभी एक त्रुटि फिसल जाती है: 2.5 तक, आपको कॉल करना था foo.next()- 2.6 में, जबकि वह अभी भी पीछे की संगतता के लिए काम करता है, आपको कॉल करना चाहिए next(foo), और 3.*, __next__"oops-eye" के बजाय मैजिक विधि को सही ढंग से नाम दिया गया है next! - )।

इसलिए सामान्य नियम यह होना चाहिए कि आप कभी भी जादू की विधि को सीधे न कहें (लेकिन हमेशा अप्रत्यक्ष रूप से एक अंतर्निहित के माध्यम से) जब तक कि आपको ठीक-ठीक पता न हो कि आपको ऐसा करने की आवश्यकता क्यों है (उदाहरण के लिए, जब आप उप-वर्ग में ऐसी विधि को ओवरराइड कर रहे हों, यदि उपवर्ग को उस सुपरक्लास को टालने की जरूरत है जो जादू की विधि से स्पष्ट रूप से किया जाना चाहिए)।


मैं शुरुआत करने वाला पायथन उपयोगकर्ता हूं (शुरुआती प्रोग्रामर ने नहीं सोचा था) और मुझे इस बात पर यकीन नहीं है कि "जब आप लेन-इन बिल में कॉल देखते हैं, तो आपको यकीन है कि, यदि प्रोग्राम अपवाद के बजाय जारी रहता है"। मैंने यह कोशिश की: def len(x): return "I am a string." print(len(42)) print(len([1,2,3]))और यह I am stringदो बार छपी । क्या आप इसे और अधिक समझा सकते हैं?
— डेरेक नादज़ा

4
@ DarekN Ddza इससे ऊपर का कोई लेना-देना नहीं है, जो बिलिन लेन के बारे में है। आपने अपने लेन फ़ंक्शन को परिभाषित किया है, जो निश्चित रूप से आप जो चाहें वापस कर सकते हैं। ओपी ने बिल्डिन लेन के बारे में बात की, जो कि विचाराधीन वस्तु पर __len__विशेष विधि (फ़ंक्शन नहीं) कहती है ।
— Veky

@Veky मुझे यह कैसे सुनिश्चित किया जा सकता है कि मैं बिल्ट-इन फ़ंक्शन को कॉल कर रहा हूं न कि lenकुछ अन्य फ़ंक्शन (जैसे मेरे उदाहरण में) जो उसी नाम का हुआ है - len। "आप अंतर्निहित फ़ंक्शन लेन को पुनर्परिभाषित कर रहे हैं" या इस तरह की कोई चेतावनी नहीं है। मेरी राय में, मुझे यकीन नहीं हो सकता है कि एलेक्स ने अपने जवाब में क्या कहा था।
— डारेक नादज़ा

3
एलेक्स ने स्पष्ट रूप से कहा कि यदि आप बिलिन को बुला रहे हैं, तो आप निश्चित हैं ..._। उन्होंने कहा कि आप बिलिन को बुला रहे हैं यह सुनिश्चित करने के बारे में कुछ भी नहीं कहा गया है। लेकिन अगर आपको लगता है कि जानना चाहता हूँ, आप कर सकते हैं: len in vars(__builtins__).values()।
— विक्की

1
अफसोस की बात है, पायथन में वस्तुओं के लिए एक सामान्य आधार वर्ग की कमी का यह एक और उदाहरण है। Syntactic संदर्भ स्विचन हमेशा अखरोट का होता है। कुछ मामलों में यह एक अंडरस्कोर विधि का उपयोग करने के लिए सामान्य मुहावरा है, दूसरों में कई वस्तुओं के लिए कुछ सामान्य करने के लिए एक फ़ंक्शन की तरह कुछ का उपयोग करना चाहिए। यह भी अजीब है क्योंकि कई वस्तुओं का लेन के लिए कोई शब्दार्थ उपयोग नहीं है। कभी-कभी ऑब्जेक्ट मॉडल अधिक C ++ की तरह होता है, किचन सिंक ..
— uchuugaka

28

आप लेन के बारे में सोच सकते हैं () के बराबर होने के नाते

def len(x):
    return x.__len__()

एक लाभ यह है कि यह आपको चीजों को लिखने की अनुमति देता है

somelist = [[1], [2, 3], [4, 5, 6]]
map(len, somelist) 

के बजाय

map(list.__len__, somelist)

या

map(operator.methodcaller('__len__'), somelist)

हालांकि थोड़ा अलग व्यवहार है। उदाहरण के लिए 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()

2
मुझे लगता है कि आप के operator.methodcallerबजाय मतलब है operator.attrgetter।
— एलाज़ार

5

आप पायथंड डॉक्स की जांच कर सकते हैं :

>>> 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
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.