2012-04-06 14 views
95

पायथन में एक सामान्य एंटीपाटरन एक लूप में + का उपयोग कर तारों के अनुक्रम को जोड़ना है। यह बुरा है क्योंकि पाइथन दुभाषिया को प्रत्येक पुनरावृत्ति के लिए एक नई स्ट्रिंग ऑब्जेक्ट बनाना है, और यह वर्गबद्ध समय लेता है। (कुछ मामलों में सीपीथॉन के हाल के संस्करण स्पष्ट रूप से इसे अनुकूलित कर सकते हैं, लेकिन अन्य कार्यान्वयन नहीं कर सकते हैं, इसलिए प्रोग्रामर इस पर भरोसा करने से हतोत्साहित हैं।) ''.join ऐसा करने का सही तरीका है।दो तारों को जोड़ने के लिए '+' का उपयोग न करने का कोई कारण नहीं है?

हालांकि, मैंने सुना है यह कहा (including here on Stack Overflow) आप कभी नहीं, स्ट्रिंग संयोजन के लिए कभी उपयोग +, लेकिन इसके बजाय हमेशा ''.join या एक प्रारूप स्ट्रिंग का उपयोग करना चाहिए। मुझे समझ में नहीं आता कि यह मामला क्यों है यदि आप केवल दो तारों को जोड़ रहे हैं। अगर मेरी समझ सही है, तो इसे वर्गबद्ध समय नहीं लेना चाहिए, और मुझे लगता है कि a + b क्लीनर और ''.join((a, b)) या '%s%s' % (a, b) से अधिक पठनीय है।

क्या दो स्ट्रिंग्स को जोड़ने के लिए + का उपयोग करना अच्छा अभ्यास है? या क्या कोई समस्या है जिसके बारे में मुझे पता नहीं है?

+0

इसके neater (पाद टिप्पणी [6] देखें) और आप संयोजन ऐसा नहीं करने के लिए अधिक नियंत्रण है। लेकिन इसकी थोड़ी धीमी, स्ट्रिंग बाशिंग व्यापार बंद: पी –

+0

क्या आप कह रहे हैं कि '+' तेज या धीमा है? और क्यों? – Taymon

+1

+, तेजी से होता है '[2] में:% timeit" एक "* 80 +" बी "* 80' ' 1000000 छोरों, 3 का सबसे अच्छा: loop' प्रति 356 एनएस '[3]:% टाइमिट "% s% s"% ("a" * 80, "बी" * 80) ' ' 1000000 लूप, 3: 907 एनएस प्रति लूप ' –

उत्तर

83

दो+ के साथ स्ट्रिंग्स में कुछ भी गलत नहीं है। दरअसल ''.join([a, b]) से पढ़ना आसान है।

आप सही हैं हालांकि + के साथ 2 से अधिक तारों को संयोजित करना एक ओ (एन^2) ऑपरेशन है (ओ (एन) की तुलना में join के लिए) और इस प्रकार अक्षम हो जाता है। हालांकि यह एक लूप का उपयोग करने के साथ नहीं है। यहां तक ​​कि a + b + c + ... ओ (एन^2) है, इसका कारण यह है कि प्रत्येक concatenation एक नई स्ट्रिंग पैदा करता है।

CPython2.4 और बाद वाले वर्शन इसे कम करने का प्रयास करें, लेकिन फिर भी 2 से अधिक तारों को संयोजित करते समय join का उपयोग करने की सलाह दी जाती है।

+4

आपका मतलब है ''। जॉइन ((ए, बी)) सही? – Mutant

+2

@Mutant: '.join' एक पुनरावृत्त लेता है, इसलिए दोनों .join ([a, b])' और '.join ((a, b)) 'मान्य हैं। – foundling

+0

सीपीथॉन 2.3+ के लिए भी http://stackoverflow.com/a/12171382/378826 (लेनेर्ट रीगेब्रो से) पर स्वीकार्य उत्तर (2013 से) में '+' या '+ =' का उपयोग करने पर दिलचस्प समय संकेत मिलता है और केवल चुने गए यदि यह स्पष्ट व्यक्ति समस्या समाधान समाधान के विचार को उजागर करता है तो "संलग्न/जुड़ें" पैटर्न। – Dilettant

42

प्लस ऑपरेटर दो पायथन स्ट्रिंग्स को संयोजित करने के लिए बिल्कुल ठीक समाधान है। लेकिन यदि आप दो से अधिक तार (एन> 25) जोड़ते रहते हैं, तो आप कुछ और सोचना चाहेंगे।

''.join([a, b, c]) चाल एक प्रदर्शन अनुकूलन है।

+2

क्या एक सूची में एक टुपल बेहतर नहीं होगा? – ThiefMaster

+5

ट्यूपल तेज़ होगा - कोड सिर्फ एक उदाहरण था :) आमतौर पर लंबे एकाधिक स्ट्रिंग इनपुट गतिशील होते हैं। –

+0

@Mikko Ohtamaa: गतिशील तार tuples में रखा जा सकता है। – martineau

5

धारणा है कि किसी को कभी भी स्ट्रिंग कॉन्सटेनेशन के लिए + कभी भी उपयोग नहीं करना चाहिए, बल्कि इसके बजाय हमेशा '' का उपयोग करें। जॉइन मिथक हो सकता है। यह सच है कि + का उपयोग अपरिवर्तनीय स्ट्रिंग ऑब्जेक्ट की अनावश्यक अस्थायी प्रतियां बनाता है लेकिन अन्य उद्धृत तथ्य यह नहीं है कि एक लूप में join को कॉल करना आमतौर पर function call का ओवरहेड जोड़ देगा। चलिए अपना उदाहरण लेते हैं।

दो सूचियों, लिंक किए गए तो सवाल से और दूसरा एक बड़ा बनाएं गढ़े

>>> myl1 = ['A','B','C','D','E','F'] 
>>> myl2=[chr(random.randint(65,90)) for i in range(0,10000)] 

संबंधित join और + कार्यक्षमता का उपयोग करने के लिए दो काम करता है, UseJoin और UsePlus करने देता है।

>>> def UsePlus(): 
    return [myl[i] + myl[i + 1] for i in range(0,len(myl), 2)] 

>>> def UseJoin(): 
    [''.join((myl[i],myl[i + 1])) for i in range(0,len(myl), 2)] 

पहली सूची

>>> myl=myl1 
>>> t1=timeit.Timer("UsePlus()","from __main__ import UsePlus") 
>>> t2=timeit.Timer("UseJoin()","from __main__ import UseJoin") 
>>> print "%.2f usec/pass" % (1000000 * t1.timeit(number=100000)/100000) 
2.48 usec/pass 
>>> print "%.2f usec/pass" % (1000000 * t2.timeit(number=100000)/100000) 
2.61 usec/pass 
>>> 

वे लगभग एक ही क्रम के साथ timeit चलाने देता है।

चलें उपयोग cProfile

>>> myl=myl2 
>>> cProfile.run("UsePlus()") 
     5 function calls in 0.001 CPU seconds 

    Ordered by: standard name 

    ncalls tottime percall cumtime percall filename:lineno(function) 
     1 0.001 0.001 0.001 0.001 <pyshell#1376>:1(UsePlus) 
     1 0.000 0.000 0.001 0.001 <string>:1(<module>) 
     1 0.000 0.000 0.000 0.000 {len} 
     1 0.000 0.000 0.000 0.000 {method 'disable' of '_lsprof.Profiler' objects} 
     1 0.000 0.000 0.000 0.000 {range} 


>>> cProfile.run("UseJoin()") 
     5005 function calls in 0.029 CPU seconds 

    Ordered by: standard name 

    ncalls tottime percall cumtime percall filename:lineno(function) 
     1 0.015 0.015 0.029 0.029 <pyshell#1388>:1(UseJoin) 
     1 0.000 0.000 0.029 0.029 <string>:1(<module>) 
     1 0.000 0.000 0.000 0.000 {len} 
     1 0.000 0.000 0.000 0.000 {method 'disable' of '_lsprof.Profiler' objects} 
    5000 0.014 0.000 0.014 0.000 {method 'join' of 'str' objects} 
     1 0.000 0.000 0.000 0.000 {range} 

और यह लग रहा है कि का उपयोग कर में शामिल हों, अनावश्यक फ़ंक्शन कॉल जो भूमि के ऊपर करने के लिए जोड़ सकते हैं में परिणाम है।

अब सवाल पर वापस आ रहा है। क्या किसी को +join पर सभी मामलों में उपयोग को हतोत्साहित करना चाहिए?

मेरा मानना ​​है कि नहीं, बातें प्रश्न

  • कड़ी ऑपरेशन का कोई में स्ट्रिंग की

    1. लंबाई को ध्यान में रखा जाना चाहिए।

    और विकास पूर्व-परिपक्व अनुकूलन में ऑफ-कोर्स बुरा है।

  • +7

    बेशक, विचार लूप के अंदर 'जॉइन' का उपयोग नहीं करना होगा - बल्कि लूप एक अनुक्रम जेनरेट करेगा जो शामिल होने के लिए पारित किया जाएगा। – jsbueno

    2

    मैं एक त्वरित परीक्षण किया है:

    import sys 
    
    str = e = "a xxxxxxxxxx very xxxxxxxxxx long xxxxxxxxxx string xxxxxxxxxx\n" 
    
    for i in range(int(sys.argv[1])): 
        str = str + e 
    

    और यह समय समाप्त हो गया:

    [email protected]:/binks/micks/ruby/tests$ time python /binks/micks/junk/strings.py 8000000 
    8000000 times 
    
    real 0m2.165s 
    user 0m1.620s 
    sys  0m0.540s 
    [email protected]:/binks/micks/ruby/tests$ time python /binks/micks/junk/strings.py 16000000 
    16000000 times 
    
    real 0m4.360s 
    user 0m3.480s 
    sys  0m0.870s 
    

    वहाँ जाहिरा तौर पर a = a + b मामले के लिए एक अनुकूलन है। यह ओ (एन^2) समय प्रदर्शित नहीं करता है क्योंकि किसी को संदेह हो सकता है।

    तो कम से कम + का उपयोग करके प्रदर्शन के संदर्भ में ठीक है।

    +2

    आप यहां "शामिल" मामले की तुलना कर सकते हैं। और अन्य पायथन कार्यान्वयन की बात है, जैसे कि पाइप, ज्योथन, लोहेप्थाथन, आदि ... – jsbueno

    6

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

    कहो, एक समारोह एक बहस की आवश्यकता है, और आप इसे एक स्ट्रिंग प्राप्त करने की उम्मीद कर लिखें:

    In [1]: def foo(zeta): 
        ...:  print 'bar: ' + zeta 
    
    In [2]: foo('bang') 
    bar: bang 
    

    तो, इस फ़ंक्शन का उपयोग पूरे कोड में अक्सर किया जा सकता है। आपके सहकर्मियों को यह पता हो सकता है कि यह वास्तव में क्या करता है, लेकिन आंतरिक रूप से पूरी तरह से गति से नहीं होना चाहिए, और यह नहीं पता कि फ़ंक्शन एक स्ट्रिंग की अपेक्षा करता है। और इसलिए वे इस के साथ खत्म हो सकता है:

    In [3]: foo(23) 
    --------------------------------------------------------------------------- 
    TypeError         Traceback (most recent call last) 
    
    /home/izkata/<ipython console> in <module>() 
    
    /home/izkata/<ipython console> in foo(zeta) 
    
    TypeError: cannot concatenate 'str' and 'int' objects 
    

    कोई समस्या है, तो आप सिर्फ एक प्रारूप स्ट्रिंग इस्तेमाल किया होगा:

    In [1]: def foo(zeta): 
        ...:  print 'bar: %s' % zeta 
        ...:  
        ...:  
    
    In [2]: foo('bang') 
    bar: bang 
    
    In [3]: foo(23) 
    bar: 23 
    

    ही वस्तुओं कि __str__ परिभाषित के सभी प्रकार, के लिए सच है जो साथ ही में पारित किया जा सकता है:

    In [1]: from datetime import date 
    
    In [2]: zeta = date(2012, 4, 15) 
    
    In [3]: print 'bar: ' + zeta 
    --------------------------------------------------------------------------- 
    TypeError         Traceback (most recent call last) 
    
    /home/izkata/<ipython console> in <module>() 
    
    TypeError: cannot concatenate 'str' and 'datetime.date' objects 
    
    In [4]: print 'bar: %s' % zeta 
    bar: 2012-04-15 
    

    तो हाँ: यदि आप एक प्रारूप स्ट्रिंग उपयोग कर सकते हैं कर यह और क्या अजगर है की करने के लिए लाभ ले प्रस्ताव।

    +1

    +1 एक अच्छी तरह से तर्कहीन असंतोष राय के लिए। मुझे अभी भी लगता है कि मैं '+' का पक्ष लेता हूं। – Taymon

    +0

    आप केवल foo विधि को परिभाषित क्यों नहीं करेंगे: प्रिंट 'बार:' + str (zeta)? – EngineerWithJava54321

    +0

    @ EngineerWithJava54321 एक उदाहरण के लिए, 'zeta = u "a \ xac \ u1234 \ u20ac \ U00008000" '- इसलिए आपको' प्रिंट 'बार का उपयोग करना होगा:' + यूनिकोड (जेता) 'यह सुनिश्चित करने के लिए कि यह त्रुटि नहीं है । '% s' इसके बारे में सोचने के बिना सही है, और बहुत छोटा – Izkata

    -3

    '' .join ([क, ख])+ की तुलना में बेहतर समाधान है।

    क्योंकि कोड एक तरीका है कि अजगर की नहीं नुकसान अन्य कार्यान्वयन करता है में लिखा जाना चाहिए (PyPy, Jython, IronPython, Cython, Psyco, और इस तरह)

    प्रपत्र एक + = ख या एक = ए + बी है सीपीथॉन में भी नाजुक है और कार्यान्वयन में बिल्कुल मौजूद नहीं है जोका उपयोग नहीं करते(संदर्भ गणना एक ऑब्जेक्ट, ब्लॉक जैसे संसाधनों के संदर्भों, पॉइंटर्स या हैंडल की संख्या को संग्रहीत करने की तकनीक है मेमोरी, डिस्क स्पेस या अन्य संसाधन)

    https://www.python.org/dev/peps/pep-0008/#programming-recommendations

    +0

    'ए + = बी' पायथन के सभी कार्यान्वयन में काम करता है, यह सिर्फ इतना है कि उनमें से कुछ पर यह एक समय के भीतर किया जाता है जब एक लूप_ के अंदर किया जाता है; सवाल एक लूप के स्ट्रिंग concatenation _outside_ के बारे में था। – Taymon

    2

    पायथन डॉक्स के अनुसार, str.join() का उपयोग करके आपको पायथन के विभिन्न कार्यान्वयन में प्रदर्शन स्थिरता मिल जाएगी। हालांकि सीपीथॉन एस = एस + टी के वर्गबद्ध व्यवहार को दूर करता है, अन्य पायथन कार्यान्वयन नहीं हो सकता है।

    CPython कार्यान्वयन विस्तार: रों और टी दोनों तार कर रहे हैं, इस तरह के CPython के रूप में कुछ अजगर कार्यान्वयन आमतौर पर प्रपत्र एस = एस के कार्य के लिए एक में जगह अनुकूलन प्रदर्शन कर सकते हैं + टी या रों + = टी। जब लागू होता है, तो यह अनुकूलन वर्गबद्ध रन-टाइम को कम संभव बनाता है। यह अनुकूलन दोनों संस्करण और कार्यान्वयन निर्भर है। प्रदर्शन संवेदनशील कोड के लिए, str.join() विधि का उपयोग करना बेहतर है जो लगातार रैखिक concatenation संस्करणों और कार्यान्वयन में प्रदर्शन का आश्वासन देता है।

    Sequence Types in Python docs

    संबंधित मुद्दे

     संबंधित मुद्दे