python - पाइथन में विभिन्न प्रकारों को उलटा और क्रमबद्ध क्यों किया जाता है?




types python-internals (2)

reversed का प्रकार "प्रकार" है:

>>> type(reversed)
<class 'type'>

sorted प्रकार "बिल्ड फ़ंक्शन या विधि" है:

>>> type(sorted)
<class 'builtin_function_or_method'>

हालांकि, वे प्रकृति में समान लगते हैं। कार्यक्षमता में स्पष्ट अंतर को छोड़कर (क्रम बनाम बनाम अनुक्रम), कार्यान्वयन में इस अंतर का कारण क्या है?


reversed और sorted बीच क्या अंतर है?

दिलचस्प है, reversed एक समारोह नहीं है, जबकि sorted है।

एक REPL सत्र खोलें और help(reversed) टाइप करें:

class reversed(object)
 |  reversed(sequence) -> reverse iterator over values of the sequence
 |  
 |  Return a reverse iterator

यह वास्तव में एक वर्ग है जो रिवर्स इटरेटर को वापस करने के लिए उपयोग किया जाता है।

ठीक है, इसलिए reversed एक समारोह नहीं है। पर क्यों नहीं?

इसका उत्तर देना थोड़ा कठिन है। एक स्पष्टीकरण यह है कि पुनरावृत्तियों का आलसी मूल्यांकन होता है। इसके लिए किसी प्रकार के कंटेनर को किसी भी समय इट्रेटर की वर्तमान स्थिति के बारे में जानकारी संग्रहीत करने की आवश्यकता होती है। यह एक वस्तु के माध्यम से सबसे अच्छा किया जाता है, और इसलिए, एक class


अंतर यह है कि reversed एक इटैलर है (यह आलसी-मूल्यांकन भी है) और sorted एक फ़ंक्शन है जो "उत्सुकता से" काम करता है।

सभी अंतर्निहित पुनरावृत्तियों (कम से कम अजगर -x में) map , zip , filter , reversed जैसे ... को कक्षाओं के रूप में लागू किया जाता है। हालांकि उत्सुक ऑपरेटिंग बिल्ट-इन कार्य हैं , जैसे min , max , any , all और sorted

>>> a = [1,2,3,4]
>>> r = reversed(a)
<list_reverseiterator at 0x2187afa0240>

आपको वास्तव में मूल्यों को प्राप्त करने के लिए पुनरावृत्ति करने वाले को "उपभोग" करने की आवश्यकता है (उदाहरण के list ):

>>> list(r)
[4, 3, 2, 1]

दूसरी ओर इस "भस्म" भाग को sorted कार्यों की आवश्यकता नहीं है:

>>> s = sorted(a)
[1, 2, 3, 4]

टिप्पणियों में यह पूछा गया था कि इन कार्यों के बजाय कक्षाओं के रूप में क्यों लागू किया गया है । यह जवाब देने के लिए वास्तव में आसान नहीं है, लेकिन मैं अपनी पूरी कोशिश करूँगा:

आलसी-मूल्यांकन कार्यों का उपयोग करने का एक बड़ा लाभ है: जंजीर होने पर वे बहुत स्मृति कुशल होते हैं। जब तक उन्हें स्पष्ट रूप से "अनुरोध" नहीं किया जाता है, तब तक उन्हें मध्यवर्ती सूची बनाने की आवश्यकता नहीं है। यही कारण था कि map , zip और filter को उत्सुक-संचालन कार्यों (पायथन-2. x) से बदलकर आलसी-ऑपरेटिंग कक्षाओं (पायथन-3. x) में बदल दिया गया था।

आम तौर पर पायथन बनाने के लिए पायथन में दो तरीके हैं:

  • कक्षाएं जो अपने __iter__ विधि में return self __iter__
  • जनरेटर फ़ंक्शंस - ऐसे फ़ंक्शंस जिनमें yield

हालाँकि (कम से कम CPython) C. में अपने सभी अंतर्निहित इन्स (और कई मानक पुस्तकालय मॉड्यूल) को लागू करता है। C में इटैटर कक्षाएं बनाना बहुत आसान है, लेकिन पायथन-सी के आधार पर जनरेटर फ़ंक्शन बनाने के लिए मुझे कोई समझदार तरीका नहीं मिला है -API। इसलिए इन पुनरावृत्तियों को कक्षाओं (सीपीथॉन में) के रूप में लागू करने का कारण सिर्फ सुविधा या (तेज या कार्यान्वयन योग्य) विकल्पों की कमी हो सकती है।

जनरेटर के बजाय कक्षाओं का उपयोग करने का एक अतिरिक्त कारण है: आप कक्षाओं के लिए विशेष तरीकों को लागू कर सकते हैं लेकिन आप उन्हें जनरेटर कार्यों पर लागू नहीं कर सकते। यह प्रभावशाली नहीं लग सकता है लेकिन इसके निश्चित फायदे हैं। उदाहरण के लिए अधिकांश __reduce__ को __reduce__ और __setstate__ विधियों का उपयोग करके (कम से कम पायथन-3. __reduce__ ) चुना जा सकता है। इसका मतलब है कि आप उन्हें डिस्क पर स्टोर कर सकते हैं, और उन्हें कॉपी करने की अनुमति दे सकते हैं। पाइथन __length_hint__ बाद से कुछ __length_hint__ भी लागू __length_hint__ जो इन __length_hint__ को list (और समान) के साथ बहुत तेजी से उपभोग करता है।

ध्यान दें कि reversed आसानी से फैक्ट्री-फंक्शन (जैसे iter ) के रूप में लागू किया जा सकता है, लेकिन iter विपरीत, जो दो अद्वितीय वर्गों को reversed कर सकता है, reversed केवल एक अद्वितीय वर्ग वापस कर सकता है।

संभावित (और अद्वितीय) वर्गों को समझाने के लिए आपको एक ऐसे वर्ग पर विचार करना होगा, जिसमें कोई __iter__ और कोई __reversed__ विधि नहीं है, लेकिन __getitem__ और __len__ __getitem__ ( __getitem__ और __len__ को लागू __len__ ) हैं:

class A(object):
    def __init__(self, vals):
        self.vals = vals

    def __len__(self):
        return len(self.vals)

    def __getitem__(self, idx):
        return self.vals[idx]

और जबकि यह समझ में आता है कि एब्सट्रैक्शन लेयर (फैक्ट्री फंक्शन) को जोड़ने के मामले में - क्योंकि लौटा हुआ वर्ग इनपुट तर्कों की संख्या पर निर्भर करता है:

>>> iter(A([1,2,3]))
<iterator at 0x2187afaed68>
>>> iter(min, 0)   # actually this is a useless example, just here to see what it returns
<callable_iterator at 0x1333879bdd8>

यह तर्क reversed लागू नहीं होता reversed :

>>> reversed(A([1,2,3]))
<reversed at 0x2187afaec50>






python-internals