मैं पायथन में एक स्ट्रिंग को दूसरे से जोड़ने के लिए एक कुशल तरीका चाहता हूं, निम्नलिखित के अलावा।
var1 = "foo"
var2 = "bar"
var3 = var1 + var2
उपयोग करने के लिए कोई अच्छी अंतर्निहित विधि है?
मैं पायथन में एक स्ट्रिंग को दूसरे से जोड़ने के लिए एक कुशल तरीका चाहता हूं, निम्नलिखित के अलावा।
var1 = "foo"
var2 = "bar"
var3 = var1 + var2
उपयोग करने के लिए कोई अच्छी अंतर्निहित विधि है?
जवाबों:
यदि आपके पास केवल एक स्ट्रिंग का संदर्भ है और आप अंत तक किसी अन्य स्ट्रिंग को संक्षिप्त करते हैं, तो CPython अब इस पर विशेष केस करता है और स्ट्रिंग को जगह में विस्तारित करने का प्रयास करता है।
अंतिम परिणाम यह है कि ऑपरेशन को परिशोधित ओ (एन) है।
जैसे
s = ""
for i in range(n):
s+=str(i)
O (n ^ 2) हुआ करता था, लेकिन अब यह O (n) है।
स्रोत से (bytesobject.c):
void
PyBytes_ConcatAndDel(register PyObject **pv, register PyObject *w)
{
PyBytes_Concat(pv, w);
Py_XDECREF(w);
}
/* The following function breaks the notion that strings are immutable:
it changes the size of a string. We get away with this only if there
is only one module referencing the object. You can also think of it
as creating a new string object and destroying the old one, only
more efficiently. In any case, don't use this if the string may
already be known to some other part of the code...
Note that if there's not enough memory to resize the string, the original
string object at *pv is deallocated, *pv is set to NULL, an "out of
memory" exception is set, and -1 is returned. Else (on success) 0 is
returned, and the value in *pv may or may not be the same as on input.
As always, an extra byte is allocated for a trailing \0 byte (newsize
does *not* include that), and a trailing \0 byte is stored.
*/
int
_PyBytes_Resize(PyObject **pv, Py_ssize_t newsize)
{
register PyObject *v;
register PyBytesObject *sv;
v = *pv;
if (!PyBytes_Check(v) || Py_REFCNT(v) != 1 || newsize < 0) {
*pv = 0;
Py_DECREF(v);
PyErr_BadInternalCall();
return -1;
}
/* XXX UNREF/NEWREF interface should be more symmetrical */
_Py_DEC_REFTOTAL;
_Py_ForgetReference(v);
*pv = (PyObject *)
PyObject_REALLOC((char *)v, PyBytesObject_SIZE + newsize);
if (*pv == NULL) {
PyObject_Del(v);
PyErr_NoMemory();
return -1;
}
_Py_NewReference(*pv);
sv = (PyBytesObject *) *pv;
Py_SIZE(sv) = newsize;
sv->ob_sval[newsize] = '\0';
sv->ob_shash = -1; /* invalidate cached hash value */
return 0;
}
अनुभवजन्य रूप से सत्यापित करना काफी आसान है।
$ python -m timeit -s "s = '" "i for xrange (10): s + =' a '" 1000000 लूप्स, सर्वश्रेष्ठ 3: 1.85 usec प्रति लूप $ python -m timeit -s "s = '" "i for xrange (100): s + =' a '" 10000 लूप, सर्वश्रेष्ठ 3: 16.8 usec प्रति लूप $ python -m timeit -s "s = '" "i for xrange (1000): s + =' a '" 10000 लूप, 3 का सर्वश्रेष्ठ: 158 प्रति लूप $ python -m timeit -s "s = '" "i for xrange (10000): s + =' a '" 1000 लूप, सर्वश्रेष्ठ 3: 1.71 मिसे प्रति लूप $ python -m timeit -s "s = '" "i for xrange (100000): s + =' a '" 10 लूप, सर्वश्रेष्ठ 3: 14.6 मिसेक प्रति लूप $ python -m timeit -s "s = '" "i for xrange (1000000): s + =' a '" 10 लूप, सर्वश्रेष्ठ 3: 173 मिसेक प्रति लूप
हालांकि यह ध्यान रखना महत्वपूर्ण है कि यह अनुकूलन पायथन युक्ति का हिस्सा नहीं है। यह केवल cPython कार्यान्वयन में है जहाँ तक मुझे पता है। उदाहरण के लिए pypy या jython पर समान अनुभवजन्य परीक्षण पुराने O (n ** 2) प्रदर्शन दिखा सकता है।
$ pypy -m timeit -s "s = '" "i for xrange (10): s + = a'" " 10000 लूप, सर्वश्रेष्ठ 3: 90.8 usec प्रति लूप $ pypy -m timeit -s "s = '" "i for xrange (100): s + = a'" " 1000 लूप, 3 का सर्वश्रेष्ठ: 896 प्रति लूप usec $ pypy -m timeit -s "s = '" "i for xrange (1000): s + = a'" " 100 लूप, सर्वश्रेष्ठ 3: 9.03 मिसे प्रति लूप $ pypy -m timeit -s "s = '" "i for xrange (10000): s + =' a" " 10 लूप, सर्वश्रेष्ठ 3: 89.5 मिसेक प्रति लूप
अब तक तो अच्छा है, लेकिन फिर,
$ pypy -m timeit -s "s = '" "i for xrange (100000): s + =' a '" 10 लूप, सर्वश्रेष्ठ 3: 12.8 प्रति लूप सेकेंड
चतुष्कोणीय से भी बदतर ouch। तो pypy कुछ ऐसा कर रहा है जो छोटे तार के साथ अच्छा काम करता है, लेकिन बड़े तार के लिए खराब प्रदर्शन करता है।
PyString_ConcatAndDel
फ़ंक्शन को उद्धृत किया है, लेकिन इसके लिए टिप्पणी शामिल की है _PyString_Resize
। इसके अलावा, टिप्पणी वास्तव में बिग-ओ
"".join(str_a, str_b)
समय से पहले अनुकूलन न करें। यदि आपके पास यह मानने का कोई कारण नहीं है कि स्ट्रिंग के संघनन के कारण गति की अड़चन है, तो बस साथ रहें +
और +=
:
s = 'foo'
s += 'bar'
s += 'baz'
कहा कि, यदि आप जावा के स्ट्रिंगब्यूलर जैसी किसी चीज के लिए लक्ष्य कर रहे हैं, तो विहित पायथन मुहावरे में किसी सूची में आइटम जोड़ना है और फिर str.join
अंत में उन सभी का उपयोग करना है:
l = []
l.append('foo')
l.append('bar')
l.append('baz')
s = ''.join(l)
str1 = "Hello"
str2 = "World"
newstr = " ".join((str1, str2))
यह विभाजक के रूप में str1 और str2 को एक स्थान से जोड़ता है। आप यह भी कर सकते हैं "".join(str1, str2, ...)
। str.join()
एक पुनरावृत्ति लेता है, इसलिए आपको स्ट्रिंग्स को एक सूची या टुपल में रखना होगा।
यह एक निर्माण विधि के लिए जितना कुशल है उतना ही इसके बारे में है।
मत करो।
यही है, ज्यादातर मामलों के लिए आप एक बार में पूरे स्ट्रिंग को उत्पन्न करने से बेहतर होते हैं, फिर मौजूदा स्ट्रिंग के लिए संलग्न होते हैं।
उदाहरण के लिए, ऐसा न करें: obj1.name + ":" + str(obj1.count)
इसके बजाय: उपयोग करें "%s:%d" % (obj1.name, obj1.count)
यह पढ़ने में आसान और अधिक कुशल होगा।
"<div class='" + className + "' id='" + generateUniqueId() + "'>" + message_text + "</div>"
, मुझे तब कम पठनीय और त्रुटिपूर्ण लगता है"<div class='{classname}' id='{id}'>{message_text}</div>".format(classname=class_name, message_text=message_text, id=generateUniqueId())
अजगर 3.6 हमें एफ-स्ट्रिंग्स देता है , जो एक खुशी है:
var1 = "foo"
var2 = "bar"
var3 = f"{var1}{var2}"
print(var3) # prints foobar
आप घुंघराले ब्रेस के अंदर सबसे ज्यादा कुछ भी कर सकते हैं
print(f"1 + 1 == {1 + 1}") # prints 1 + 1 == 2
यदि आपको एक बड़ी स्ट्रिंग बनाने के लिए कई परिशिष्ट संचालन करने की आवश्यकता है, तो आप उपयोग कर सकते हैं StringIO या cStringIO। इंटरफ़ेस एक फ़ाइल की तरह है। यानी: आप write
इसमें टेक्स्ट को जोड़ सकते हैं।
यदि आप सिर्फ दो तार जोड़ रहे हैं तो बस उपयोग करें +
।
मूल रूप से, कोई अंतर नहीं। एकमात्र सुसंगत प्रवृत्ति यह है कि पायथन हर संस्करण के साथ धीमा होता जा रहा है ... :(
%%timeit
x = []
for i in range(100000000): # xrange on Python 2.7
x.append('a')
x = ''.join(x)
पायथन 2.7
1 लूप, सर्वश्रेष्ठ 3: 7.34 प्रति लूप
अजगर 3.4
1 लूप, सर्वश्रेष्ठ 3: 7.99 प्रति लूप
पायथन 3.5
1 लूप, सर्वश्रेष्ठ 3: 8.48 प्रति लूप
अजगर 3.6
1 लूप, सर्वश्रेष्ठ 3: 9.93 प्रति लूप
%%timeit
x = ''
for i in range(100000000): # xrange on Python 2.7
x += 'a'
पायथन 2.7 :
1 लूप, सर्वश्रेष्ठ 3: 7.41 प्रति लूप
अजगर 3.4
1 लूप, सर्वश्रेष्ठ 3: 9.08 एस प्रति लूप
पायथन 3.5
1 लूप, सर्वश्रेष्ठ 3: 8.82 प्रति लूप
अजगर 3.6
1 लूप, सर्वश्रेष्ठ 3: 9.24 प्रति लूप
1.19 s
और 992 ms
Python2.7 पर क्रमश:
__add__ फ़ंक्शन के साथ तार जोड़ें
str = "Hello"
str2 = " World"
st = str.__add__(str2)
print(st)
उत्पादन
Hello World
str + str2
अभी भी कम है।
a='foo'
b='baaz'
a.__add__(b)
out: 'foobaaz'
a.__add__(b)
लेखन के समान है a+b
। जब आप +
ऑपरेटर का उपयोग करते हुए तारों को समतल करते हैं , तो पायथन __add__
एक पैरामीटर के रूप में दाईं ओर स्ट्रिंग को पार करते हुए बाईं ओर स्ट्रिंग पर विधि को कॉल करेगा ।
"foo" + "bar" + str(3)