python - सूची (] से तेज [] क्यों है?




3 Answers

क्योंकि [] और {} शाब्दिक वाक्यविन्यास हैं । पाइथन सिर्फ सूची या शब्दकोश ऑब्जेक्ट्स बनाने के लिए बाइटकोड बना सकता है:

>>> import dis
>>> dis.dis(compile('[]', '', 'eval'))
  1           0 BUILD_LIST               0
              3 RETURN_VALUE        
>>> dis.dis(compile('{}', '', 'eval'))
  1           0 BUILD_MAP                0
              3 RETURN_VALUE        

list() और dict() अलग वस्तुएं हैं। उनके नामों को हल करने की आवश्यकता है, तर्क को धक्का देने के लिए ढेर को शामिल करना होगा, फ्रेम को बाद में पुनः प्राप्त करने के लिए संग्रहीत किया जाना चाहिए, और एक कॉल करना है। यह सब अधिक समय लगता है।

खाली मामले के लिए, इसका मतलब है कि आपके पास कम से कम एक LOAD_NAME (जिसे वैश्विक नामस्थान के साथ-साथ __builtin__ मॉड्यूल के माध्यम से खोजना है) उसके बाद CALL_FUNCTION , जिसे वर्तमान फ्रेम को संरक्षित करना है:

>>> dis.dis(compile('list()', '', 'eval'))
  1           0 LOAD_NAME                0 (list)
              3 CALL_FUNCTION            0
              6 RETURN_VALUE        
>>> dis.dis(compile('dict()', '', 'eval'))
  1           0 LOAD_NAME                0 (dict)
              3 CALL_FUNCTION            0
              6 RETURN_VALUE        

आप timeit साथ अलग-अलग नाम लुकअप का समय timeit :

>>> import timeit
>>> timeit.timeit('list', number=10**7)
0.30749011039733887
>>> timeit.timeit('dict', number=10**7)
0.4215109348297119

समय विसंगति शायद एक शब्दकोश हैश टकराव है। उन वस्तुओं को बुलाए जाने के समय से उन समय घटाएं, और शाब्दिक उपयोग के लिए परिणामों के मुकाबले परिणाम की तुलना करें:

>>> timeit.timeit('[]', number=10**7)
0.30478692054748535
>>> timeit.timeit('{}', number=10**7)
0.31482696533203125
>>> timeit.timeit('list()', number=10**7)
0.9991960525512695
>>> timeit.timeit('dict()', number=10**7)
1.0200958251953125

तो ऑब्जेक्ट को कॉल करने के लिए अतिरिक्त 1.00 - 0.31 - 0.30 == 0.39 सेकेंड प्रति 10 मिलियन कॉल लेते हैं।

आप वैश्विक नामों को स्थानीय लोगों के रूप में timeit करके ग्लोबल लुकअप लागत से बच सकते हैं (एक timeit सेटअप का उपयोग करके, जो भी आप किसी नाम से बंधे हैं वह स्थानीय है):

>>> timeit.timeit('_list', '_list = list', number=10**7)
0.1866450309753418
>>> timeit.timeit('_dict', '_dict = dict', number=10**7)
0.19016098976135254
>>> timeit.timeit('_list()', '_list = list', number=10**7)
0.841480016708374
>>> timeit.timeit('_dict()', '_dict = dict', number=10**7)
0.7233691215515137

लेकिन आप उस CALL_FUNCTION लागत को कभी भी पार नहीं कर सकते हैं।

मैंने हाल ही में [] और list() की प्रसंस्करण गति की तुलना की और यह जानकर आश्चर्यचकित हुआ कि [] list() से तीन गुना तेज है। मैंने {} और dict() साथ एक ही परीक्षण चलाया और परिणाम व्यावहारिक रूप से समान थे: [] और {} दोनों ने 0.128sec / million चक्र लिया, जबकि list() और dict() ने लगभग 0.428sec / million चक्र प्रत्येक को लिया।

ऐसा क्यों है? क्या करें [] और {} (और शायद () और '' भी) तुरंत कुछ रिक्त स्टॉक अक्षर की एक प्रतियां पास करते हैं जबकि उनके स्पष्ट रूप से नामित समकक्ष ( list() , dict() , tuple() , str() ) पूरी तरह से एक वस्तु बनाने के बारे में जाना, चाहे वे वास्तव में तत्व हैं या नहीं?

मुझे नहीं पता कि ये दो विधियां कैसे भिन्न हैं लेकिन मुझे पता लगाना अच्छा लगेगा। मुझे दस्तावेज़ों में या SO पर कोई जवाब नहीं मिला, और खाली ब्रैकेट की खोज करने से मुझे अपेक्षाकृत अधिक समस्याग्रस्त हो गया।

मुझे timeit.timeit("[]") और timeit.timeit("list()") , और timeit.timeit("{}") और timeit.timeit("dict()") को कॉल करके मेरे समय के परिणाम मिल गए हैं, क्रमशः सूचियों और शब्दकोशों की तुलना करने के लिए। मैं पाइथन 2.7.9 चला रहा हूँ।

मैंने हाल ही में खोज की है " यदि सच है तो 1 से कम धीमा क्यों है? " जो कि if True है if 1 के प्रदर्शन की तुलना करता है और इसी तरह के शाब्दिक-बनाम-वैश्विक परिदृश्य पर स्पर्श करना प्रतीत होता है; शायद यह भी विचार करने लायक है।




चूंकि list एक स्ट्रिंग को एक सूची ऑब्जेक्ट में बदलने के लिए एक function है, जबकि [] का उपयोग बल्ले से एक सूची बनाने के लिए किया जाता है। इसे आज़माएं (आपको अधिक समझ हो सकता है):

x = "wham bam"
a = list(x)
>>> a
["w", "h", "a", "m", ...]

जबकि

y = ["wham bam"]
>>> y
["wham bam"]

आपको एक वास्तविक सूची देता है जिसमें आप जो भी डालते हैं।




list() [] से तेज [] क्यों है?

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

यह तुरंत [] साथ एक सूची बनाता है।

मेरी व्याख्या आपको इसके लिए अंतर्ज्ञान देना चाहती है।

व्याख्या

[] आमतौर पर शाब्दिक वाक्यविन्यास के रूप में जाना जाता है।

व्याकरण में, इसे "सूची प्रदर्शन" के रूप में जाना जाता है। दस्तावेज़ों से :

एक सूची प्रदर्शन स्क्वायर ब्रैकेट में संलग्न अभिव्यक्तियों की संभावित रूप से खाली श्रृंखला है:

list_display ::=  "[" [starred_list | comprehension] "]"

एक सूची डिस्प्ले एक नई सूची वस्तु उत्पन्न करता है, सामग्री को अभिव्यक्तियों की सूची या समझ द्वारा निर्दिष्ट किया जा रहा है। जब अभिव्यक्तियों की अल्पविराम से अलग सूची की आपूर्ति की जाती है, तो इसके तत्वों का मूल्यांकन बाएं से दाएं से किया जाता है और उस क्रम में सूची ऑब्जेक्ट में रखा जाता है। जब एक समझ प्रदान की जाती है, तो सूची समझ के परिणामस्वरूप तत्वों से बनाई जाती है।

संक्षेप में, इसका मतलब है कि टाइप list की एक अंतर्निहित वस्तु बनाई गई है।

इस पर कोई बाधा नहीं है - जिसका अर्थ है कि पाइथन इसे जितनी जल्दी हो सके कर सकता है।

दूसरी तरफ, बिल्टिन सूची कन्स्ट्रक्टर का उपयोग करके एक बिल्टिन list बनाने से list() को अवरुद्ध किया जा सकता है।

उदाहरण के लिए, हम चाहते हैं कि हमारी सूचियों को शोर से बनाया जाए:

class List(list):
    def __init__(self, iterable=None):
        if iterable is None:
            super().__init__()
        else:
            super().__init__(iterable)
        print('List initialized.')

हम मॉड्यूल स्तर के वैश्विक दायरे पर नाम list को रोक सकते हैं, और फिर जब हम एक list बनाते हैं, तो हम वास्तव में हमारी उप-सूची सूची बनाते हैं:

>>> list = List
>>> l = list()
List initialized.
>>> type(l)
<class '__main__.List'>

इसी तरह हम इसे वैश्विक नामस्थान से हटा सकते हैं

del list

और इसे बिल्टिन नेमस्पेस में रखें:

import builtins
builtins.list = List

और अब:

>>> l0 = list()
List initialized.
>>> type(l0)
<class '__main__.List'>

और ध्यान दें कि सूची प्रदर्शन बिना किसी शर्त के एक सूची बनाता है:

>>> l1 = []
>>> type(l1)
<class 'list'>

हम शायद यह अस्थायी रूप से केवल ऐसा करते हैं, इसलिए हमारे परिवर्तनों को पूर्ववत करने दें - पहले बिल्टिन से नई List ऑब्जेक्ट को हटा दें:

>>> del builtins.list
>>> builtins.list
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: module 'builtins' has no attribute 'list'
>>> list()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'list' is not defined

ओह, नहीं, हम मूल का ट्रैक खो गए।

चिंता न करें, हम अभी भी list प्राप्त कर सकते हैं - यह एक सूची का प्रकार शाब्दिक है:

>>> builtins.list = type([])
>>> list()
[]

इसलिए...

list() [] से तेज [] क्यों है?

जैसा कि हमने देखा है - हम list को ओवरराइट कर सकते हैं - लेकिन हम शाब्दिक प्रकार के निर्माण को रोक नहीं सकते हैं। जब हम list उपयोग करते हैं तो हमें यह देखने के लिए लुकअप करना पड़ता है कि क्या कुछ भी है या नहीं।

फिर हमें जो भी कॉल करने योग्य दिखता है उसे कॉल करना होगा। व्याकरण से:

एक कॉल कॉल करने योग्य ऑब्जेक्ट (उदाहरण के लिए, एक फ़ंक्शन) को संभवतः तर्कों की खाली श्रृंखला के साथ कॉल करता है:

call                 ::=  primary "(" [argument_list [","] | comprehension] ")"

हम देख सकते हैं कि यह किसी भी नाम के लिए एक ही चीज़ करता है, केवल सूची नहीं:

>>> import dis
>>> dis.dis('list()')
  1           0 LOAD_NAME                0 (list)
              2 CALL_FUNCTION            0
              4 RETURN_VALUE
>>> dis.dis('doesnotexist()')
  1           0 LOAD_NAME                0 (doesnotexist)
              2 CALL_FUNCTION            0
              4 RETURN_VALUE

[] लिए पाइथन बाइटकोड स्तर पर कोई फ़ंक्शन कॉल नहीं है:

>>> dis.dis('[]')
  1           0 BUILD_LIST               0
              2 RETURN_VALUE

यह सीधे बाइटकोड स्तर पर किसी भी लुकअप या कॉल के बिना सूची बनाने के लिए सीधे चला जाता है।

निष्कर्ष

हमने दिखाया है कि स्कोपिंग नियमों का उपयोग करके list को उपयोगकर्ता कोड से अवरुद्ध किया जा सकता है, और वह list() कॉल करने योग्य लगती है और फिर इसे कॉल करती है।

जबकि [] एक सूची प्रदर्शन है, या एक शाब्दिक है, और इस प्रकार नाम लुकअप और फ़ंक्शन कॉल से बचाता है।




Related