दो तारों को समेटने के लिए '+' का उपयोग न करने का कोई कारण?


124

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

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

क्या +दो तारों को समतल करने के लिए उपयोग करना अच्छा है ? या क्या कोई समस्या है जिससे मैं अवगत नहीं हूं?


इसका नाटर और आप पर नियंत्रण नहीं करने के लिए अधिक नियंत्रण है। BUT इसके थोड़े धीमे, स्ट्रिंग बशिंग व्यापार बंद: P
जकोब बोयोर

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

1
+ तेज है, In [2]: %timeit "a"*80 + "b"*80 1000000 loops, best of 3: 356 ns per loop In [3]: %timeit "%s%s" % ("a"*80, "b"*80) 1000000 loops, best of 3: 907 ns per loop
जैकब बोयर

4
In [3]: %timeit "%s%s" % (a, b) 1000000 loops, best of 3: 590 ns per loop In [4]: %timeit a + b 10000000 loops, best of 3: 147 ns per loop
जैकब बाउयर

1
@JakobBowyer और दूसरों: "स्ट्रिंग संयोजन बुरा है" तर्क है लगभग गति के साथ कोई लेना देना नहीं है, लेकिन साथ स्वत: रूपांतरण का लाभ लेने के __str__। उदाहरणों के लिए मेरा उत्तर देखें।
इजाकाता

जवाबों:


120

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

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

CPython2.4 और इसके बाद के संस्करण को कम करने की कोशिश करते हैं, लेकिन join2 से अधिक तारों को समतल करते समय इसका उपयोग करना उचित है ।


5
@Mutant: .join, एक iterable लेता दोनों तो .join([a,b])और .join((a,b))मान्य हैं।
संस्थापक

1
दिलचस्प टाइमिंग का उपयोग +या +=स्वीकृत उत्तर में (2013 से) stackoverflow.com/a/12171382/378826 पर (लेन्नेर्ट रेगेब्र से) यहां तक ​​कि CPython 2.3+ के लिए भी किया गया है और यदि केवल इस स्पष्टता को उजागर करता है, तो "परिशिष्ट / प्रतिमान" को चुना। हाथ में समस्या समाधान के लिए विचार करें।
Dilettant

49

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

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


2
एक सूची से बेहतर नहीं होगा?
ThiefMaster

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

5
@martineau मुझे लगता है कि वह गतिशील रूप append()से एक सूची में तार पैदा करने और आईएनजी का मतलब है ।
पीटर सी

5
यहां कहने की जरूरत है: टपल आमतौर पर धीमी संरचना है, खासकर अगर यह बढ़ रहा है। सूची के साथ आप list.extend (list_of_items) और list.append (आइटम) का उपयोग कर सकते हैं जो गतिशील रूप से सामान को समेटते समय बहुत तेज़ होते हैं।
अंती हापाला

6
के लिए +1 n > 25। कहीं शुरू करने के लिए मनुष्य को संदर्भ बिंदु चाहिए।
n611x007 20

8

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

दो सूचियाँ बनाएँ, एक जुड़े SO प्रश्न से और दूसरी एक बड़ी गढ़ी हुई

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

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

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

उनके पास लगभग एक ही रनटाइम है।

चलो 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 का उपयोग करने से, अनावश्यक फ़ंक्शन कॉल में परिणाम होता है जो ओवरहेड में जोड़ सकता है।

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

मेरा मानना ​​है कि नहीं, चीजों को ध्यान में रखा जाना चाहिए

  1. प्रश्न में स्ट्रिंग की लंबाई
  2. कॉन्टेक्टेशन ऑपरेशन का नहीं।

और एक विकास में पाठ्यक्रम पूर्व परिपक्व अनुकूलन बुराई है।


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

7

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

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

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। मुझे अभी भी लगता है कि मैं एहसान करता हूँ +
तैमूर

1
आप केवल foo पद्धति को इस रूप में परिभाषित क्यों नहीं करेंगे: प्रिंट 'बार:' + स्ट्रेट (जेटा)?
EngineerWithJava54321

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

@ EngineerWithJava54321 अन्य उदाहरण यहां कम प्रासंगिक हैं, लेकिन उदाहरण के लिए, किसी अन्य भाषा में "bar: %s"अनुवाद किया जा सकता है "zrb: %s br"%sसंस्करण सिर्फ काम है, लेकिन स्ट्रिंग-concat संस्करण एक मेस सभी मामलों को संभालने के लिए बन जाएगा और आपके अनुवादकों अब से निपटने के लिए दो अलग-अलग अनुवाद होता होगा
Izkata

अगर उन्हें नहीं पता कि फू का कार्यान्वयन क्या है, तो वे किसी भी त्रुटि के साथ चलेंगे def
इंसाइडिन

3

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

import sys

str = e = "a xxxxxxxxxx very xxxxxxxxxx long xxxxxxxxxx string xxxxxxxxxx\n"

for i in range(int(sys.argv[1])):
    str = str + e

और इसे समय पर:

mslade@mickpc:/binks/micks/ruby/tests$ time python /binks/micks/junk/strings.py  8000000
8000000 times

real    0m2.165s
user    0m1.620s
sys     0m0.540s
mslade@mickpc:/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मामले के लिए एक अनुकूलन है । यह O (n ^ 2) समय को प्रदर्शित नहीं करता है क्योंकि किसी को संदेह हो सकता है।

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


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

3

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

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

पायथन डॉक्स में अनुक्रम प्रकार (पैर नोट देखें [6])



0

'' .join ([a, b]) + से बेहतर समाधान है ।

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

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

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


1
a += bअजगर के सभी कार्यान्वयन में काम करता है, यह सिर्फ इतना है कि उनमें से कुछ पर यह एक लूप के अंदर किए जाने पर द्विघात समय लगता है ; सवाल एक लूप के बाहर स्ट्रिंग के संयोजन के बारे में था ।
तैमून
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.