पायथन कोड लंबाई विधि के बजाय लेन () फ़ंक्शन का उपयोग क्यों करता है?


204

मुझे पता है कि अजगर के पास एक len()फ़ंक्शन होता है जो स्ट्रिंग के आकार को निर्धारित करने के लिए उपयोग किया जाता है, लेकिन मैं सोच रहा था कि यह स्ट्रिंग ऑब्जेक्ट का एक तरीका क्यों नहीं है।

अपडेट करें

ठीक है, मुझे एहसास हुआ कि मैं शर्मनाक रूप से गलत था। __len__()वास्तव में एक स्ट्रिंग ऑब्जेक्ट का एक तरीका है। यह स्ट्रिंग ऑब्जेक्ट्स पर लेन फ़ंक्शन का उपयोग करके पायथन में ऑब्जेक्ट ओरिएंटेड कोड को देखने के लिए अजीब लगता है। इसके अलावा, यह __len__सिर्फ लेन के बजाय नाम के रूप में देखने के लिए भी अजीब है ।

जवाबों:


180

स्ट्रिंग्स की लंबाई विधि होती है: __len__()

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

देखें नकल कंटेनर प्रकार अधिक जानकारी के लिए।

यहाँ पायथन में प्रोटोकॉल के विषय पर एक अच्छा पढ़ा गया है: पायथन और कम से कम विस्मय का सिद्धांत


124
यह मुझे आश्चर्यचकित करता है कि उपयोग करने का कारण कितना नैतिक lenहै। उन्हें लगता है कि लोगों को लागू .__len__करने के लिए मजबूर करने की तुलना में लोगों को लागू करना आसान है .len()। इसकी एक ही बात है, और एक बहुत साफ दिखता है । अगर भाषा में OOP होने वाला है __len__, तो दुनिया में क्या है बनाने की बातlen(..)
वैकल्पिक

38
बिना किसी फ़ंक्शन या लैम्ब्डा को परिभाषित करने की आवश्यकता के बिना मैप, कम, और फ़िल्टर जैसे उच्च-क्रम के कार्यों के साथ लेन, स्ट्र, आदि का उपयोग किया जा सकता है। सब कुछ OOP के आसपास नहीं घूमता, यहां तक ​​कि पायथन में भी।
एविकाटोस

11
इसके अलावा, एक प्रोटोकॉल का उपयोग करके, वे चीजों को लागू करने के वैकल्पिक तरीके प्रदान कर सकते हैं। उदाहरण के लिए, आप इसके साथ __iter__या केवल इसके साथ एक चलने योग्य बना सकते हैं __getitem__, और iter(x)दोनों तरह से काम करेंगे। आप के साथ एक प्रयोग करने योग्य-इन-bool संदर्भ वस्तु बना सकते हैं __bool__या __len__, और bool(x)किसी भी तरह से काम करेंगे। और इसी तरह। मुझे लगता है कि अर्मिन लिंक्ड पोस्ट में इस कारण को अच्छी तरह से समझाता है - लेकिन भले ही वह ऐसा क्यों न करता हो, एक बाहरी व्यक्ति द्वारा अक्सर
समझाए

8
@ इवीकाटोस: +1 "" सब कुछ ओओपी के आसपास नहीं घूमता ", लेकिन मैं" विशेष रूप से पायथन "के साथ समाप्त होता हूं , यहां तक ​​कि नहीं । पायथन (जावा, रूबी या स्मॉलटॉक के विपरीत) "शुद्ध ओओपी" भाषा बनने की कोशिश नहीं करता है; यह स्पष्ट रूप से एक "बहु प्रतिमान" भाषा है। सूची की समझ, पुनरावृत्तियों पर तरीके नहीं हैं। zipएक शीर्ष-स्तरीय फ़ंक्शन है, एक zip_withविधि नहीं है । और इसी तरह। सिर्फ इसलिए कि सब कुछ एक वस्तु है इसका मतलब यह नहीं है कि प्रत्येक वस्तु के बारे में सबसे महत्वपूर्ण चीज एक वस्तु है।
22

7
यह लेख इतना खराब लिखा गया है कि मैं इसे पढ़ने की कोशिश करने के बाद भ्रमित और क्रोधित महसूस करता हूं। "पायथन में 2.x टुपल प्रकार उदाहरण के लिए किसी भी गैर-विशेष तरीकों को उजागर नहीं करता है और फिर भी आप इसे एक स्ट्रिंग बनाने के लिए उपयोग कर सकते हैं:" पूरी बात निकट-अनिश्चित वाक्यों का एक समामेलन है।
शीशा

93

इस सवाल पर जिम का जवाब मदद कर सकता है; मैं इसे यहाँ कॉपी करता हूँ। गीडो वैन रोसुम का उद्धरण:

सबसे पहले, मैंने HCI कारणों के लिए x.len () पर len (x) चुना (def __len __ () बहुत बाद में आया)। वास्तव में दो अलग-अलग कारण हैं, दोनों HCI:

(ए) कुछ कार्यों के लिए, उपसर्ग संकेतन सिर्फ उपसर्ग की तुलना में बेहतर पढ़ता है - उपसर्ग (और इन्फिक्स!) संचालन की गणित में एक लंबी परंपरा है जो उन धारणाओं को पसंद करते हैं जहां दृश्य गणितज्ञ को एक समस्या के बारे में सोचने में मदद करते हैं। आसान की तुलना करें जिसके साथ हम एक कच्चे OO संकेतन का उपयोग करके समान कार्य करने की अनाड़ी के लिए x * (a + b) जैसे सूत्र को x a + x b में लिखते हैं ।

(b) जब मैं कोड पढ़ता हूं जो len (x) कहता है, मुझे पता है कि यह किसी चीज की लंबाई के लिए पूछ रहा है। यह मुझे दो बातें बताता है: परिणाम एक पूर्णांक है, और तर्क कुछ प्रकार के कंटेनर है। इसके विपरीत, जब मैं x.len () पढ़ता हूं, तो मुझे पहले से ही पता होना चाहिए कि x किसी प्रकार का कंटेनर है जो इंटरफ़ेस को लागू कर रहा है या एक मानक लेन () से विरासत में मिला है। भ्रम की गवाह हम कभी-कभार होते हैं जब एक वर्ग जो मैपिंग को लागू नहीं कर रहा होता है उसके पास एक () या कुंजी () विधि होती है, या ऐसी कोई चीज़ जो फ़ाइल में नहीं होती है, उसमें एक लेखन () विधि होती है।

एक ही बात को दूसरे तरीके से कहते हुए, मैं 'लेन' को एक अंतर्निहित ऑपरेशन के रूप में देखता हूं। मुझे लगता है कि खोने के लिए नफरत करता हूँ। / ... /


37

एक lenविधि है:

>>> a = 'a string of some length'
>>> a.__len__()
23
>>> a.__len__
<method-wrapper '__len__' of str object at 0x02005650>

34

अजगर एक व्यावहारिक प्रोग्रामिंग भाषा है, और के लिए कारणों len()में एक समारोह और नहीं करने की एक विधि जा रहा है str, list, dictआदि व्यावहारिक हैं।

len()में निर्मित समारोह सौदों के साथ सीधे में निर्मित प्रकार: की CPython कार्यान्वयन len()वास्तव में रिटर्न का मूल्य ob_sizeमें क्षेत्र PyVarObjectसी struct प्रतिनिधित्व करता है कि किसी भी चर-आकार में निर्मित स्मृति में वस्तु। यह एक विधि को कॉल करने की तुलना में बहुत तेज़ है - कोई विशेषता लुकअप होने की आवश्यकता नहीं है। एक संग्रह में आइटम्स की संख्या हो रही है एक आम ऑपरेशन है और के रूप में इस तरह के बुनियादी और विविध प्रकार के लिए कुशलता से काम करना होगा str, list, array.arrayआदि

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

विशेष विधियों को लागू करने से आपकी वस्तुएं पुनरावृत्ति का समर्थन कर सकती हैं, इन्फिक्स को अधिभारित कर सकती हैं, withब्लॉकों में संदर्भों का प्रबंधन कर सकती हैं। आप डेटा मॉडल को पायथन भाषा का उपयोग करने के एक तरीके के रूप में खुद सोच सकते हैं, जहां आपके द्वारा बनाई गई वस्तुओं को मूल रूप से एकीकृत किया जा सकता है।

एक दूसरा कारण, जो इस तरह से गुइडो वैन रोसुम के उद्धरणों द्वारा समर्थित है , यह है कि यह पढ़ने और लिखने की len(s)तुलना में आसान है s.len()

संकेतन len(s)उपसर्ग संकेतन के साथ एकरी संचालकों के अनुरूप है, जैसे abs(n)len()की तुलना में अधिक बार उपयोग किया जाता है abs(), और यह लिखने के लिए आसान होने के योग्य है।

एक ऐतिहासिक कारण यह भी हो सकता है: एबीसी भाषा में जो पायथन से पहले था (और इसके डिजाइन में बहुत प्रभावशाली था), वहां एक अपर संचालक लिखा गया था #sजिसका अर्थ था len(s)


12
met% python -c 'import this' | grep 'only one'
There should be one-- and preferably only one --obvious way to do it.

34
एक वस्तु के साथ काम करते समय स्पष्ट बात, निश्चित रूप से, एक विधि।
पीटर कूपर

4
@Peter: मैं फोटो साक्ष्य के साथ किसी को भी $ 20 का भुगतान करूंगा कि उन्होंने आपकी टिप्पणी को Guido की पीठ पर टैप किया। $ 50 अगर यह उसके माथे पर है।
बग

1
हाँ, पायथन डिज़ाइनर हठधर्मिता का पालन करते हैं, लेकिन वे स्वयं अपनी हठधर्मिता का सम्मान नहीं करते हैं।
काटें

2
$ अजगर -c 'यह आयात करें' | grep स्पष्ट
एड Randall

4

यहाँ कुछ शानदार जवाब हैं, और इसलिए इससे पहले कि मैं अपना खुद का कुछ रत्न प्रकाशित करूं (कोई माणिक दंड नहीं दिया गया) यहाँ पढ़ा है।

  • पायथन एक शुद्ध ओओपी भाषा नहीं है - यह एक सामान्य उद्देश्य है, बहु-प्रतिमान भाषा है जो प्रोग्रामर को उन प्रतिमानों का उपयोग करने की अनुमति देता है जिनके साथ वे सबसे अधिक सहज हैं और / या प्रतिमान जो उनके समाधान के लिए सबसे उपयुक्त हैं।
  • पायथन में प्रथम श्रेणी के कार्य हैं, इसलिए lenवास्तव में एक वस्तु है। दूसरी ओर, रूबी में प्रथम श्रेणी के कार्य नहीं हैं। तो lenफंक्शन ऑब्जेक्ट की अपनी विधियाँ हैं जिन्हें आप चलाकर निरीक्षण कर सकते हैं dir(len)

यदि आपको अपने कोड में काम करने का तरीका पसंद नहीं है, तो अपने पसंदीदा तरीके का उपयोग करके कंटेनरों को फिर से लागू करना आपके लिए मामूली है (नीचे उदाहरण देखें)।

>>> class List(list):
...     def len(self):
...         return len(self)
...
>>> class Dict(dict):
...     def len(self):
...         return len(self)
...
>>> class Tuple(tuple):
...     def len(self):
...         return len(self)
...
>>> class Set(set):
...     def len(self):
...         return len(self)
...
>>> my_list = List([1,2,3,4,5,6,7,8,9,'A','B','C','D','E','F'])
>>> my_dict = Dict({'key': 'value', 'site': 'stackoverflow'})
>>> my_set = Set({1,2,3,4,5,6,7,8,9,'A','B','C','D','E','F'})
>>> my_tuple = Tuple((1,2,3,4,5,6,7,8,9,'A','B','C','D','E','F'))
>>> my_containers = Tuple((my_list, my_dict, my_set, my_tuple))
>>>
>>> for container in my_containers:
...     print container.len()
...
15
2
15
15

0

तुम भी कह सकते हो

>> x = 'test'
>> len(x)
4

पायथन 2.7.3 का उपयोग करना।


9
lenफ़ंक्शन पिछले उत्तरों में पहले से ही उल्लेख किया गया था। इस "उत्तर" का क्या मतलब है, फिर?
पियोट्र डोब्रोगोस्ट

0

बाकी उत्तरों में से कुछ गायब है: lenफ़ंक्शन यह जाँचता है कि __len__विधि एक गैर-नकारात्मक रिटर्न करती है int। तथ्य यह lenहै कि एक फ़ंक्शन का मतलब है कि चेक से बचने के लिए कक्षाएं इस व्यवहार को ओवरराइड नहीं कर सकती हैं। जैसे, len(obj)सुरक्षा का एक स्तर देता है जो obj.len()नहीं कर सकता।

उदाहरण:

>>> class A:
...     def __len__(self):
...         return 'foo'
...
>>> len(A())
Traceback (most recent call last):
  File "<pyshell#8>", line 1, in <module>
    len(A())
TypeError: 'str' object cannot be interpreted as an integer
>>> class B:
...     def __len__(self):
...         return -1
... 
>>> len(B())
Traceback (most recent call last):
  File "<pyshell#13>", line 1, in <module>
    len(B())
ValueError: __len__() should return >= 0

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


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