728x90
반응형
질문 : 파이썬에서 한 문자열을 다른 문자열에 어떻게 추가합니까?
다음과는 달리 Python에서 한 문자열을 다른 문자열에 추가하는 효율적인 방법을 원합니다.
var1 = "foo" var2 = "bar" var3 = var1 + var2
사용할 좋은 기본 제공 방법이 있습니까?
답변
문자열에 대한 참조가 하나만 있고 다른 문자열을 끝에 연결하는 경우 CPython은 이제 특수한 경우에 해당 문자열을 제자리에서 확장하려고합니다.
최종 결과는 작업이 O (n)으로 분할되는 것입니다.
예 :
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=''" "for i in xrange(10):s+='a'"
1000000 loops, best of 3: 1.85 usec per loop
$ python -m timeit -s"s=''" "for i in xrange(100):s+='a'"
10000 loops, best of 3: 16.8 usec per loop
$ python -m timeit -s"s=''" "for i in xrange(1000):s+='a'"
10000 loops, best of 3: 158 usec per loop
$ python -m timeit -s"s=''" "for i in xrange(10000):s+='a'"
1000 loops, best of 3: 1.71 msec per loop
$ python -m timeit -s"s=''" "for i in xrange(100000):s+='a'"
10 loops, best of 3: 14.6 msec per loop
$ python -m timeit -s"s=''" "for i in xrange(1000000):s+='a'"
10 loops, best of 3: 173 msec per loop
그것은이 최적화는 파이썬 사양의 일부가 아니라는 것을 참고하지만 중요합니다. 내가 아는 한 cPython 구현에만 있습니다. 예를 들어 pypy 또는 jython에 대한 동일한 경험적 테스트는 이전 O (n ** 2) 성능을 보여줄 수 있습니다.
$ pypy -m timeit -s"s=''" "for i in xrange(10):s+='a'"
10000 loops, best of 3: 90.8 usec per loop
$ pypy -m timeit -s"s=''" "for i in xrange(100):s+='a'"
1000 loops, best of 3: 896 usec per loop
$ pypy -m timeit -s"s=''" "for i in xrange(1000):s+='a'"
100 loops, best of 3: 9.03 msec per loop
$ pypy -m timeit -s"s=''" "for i in xrange(10000):s+='a'"
10 loops, best of 3: 89.5 msec per loop
지금까지는 훌륭했지만
$ pypy -m timeit -s"s=''" "for i in xrange(100000):s+='a'"
10 loops, best of 3: 12.8 sec per loop
아야 2 차보다 더 나빠. 따라서 pypy는 짧은 문자열에서는 잘 작동하지만 큰 문자열에서는 제대로 수행되지 않습니다.
출처 : https://stackoverflow.com/questions/4435169/how-do-i-append-one-string-to-another-in-python
728x90
반응형
'프로그래밍 언어 > Python' 카테고리의 다른 글
파이썬의 자식 클래스에서 부모 클래스의 메서드를 호출하는 방법 (0) | 2021.06.16 |
---|---|
pickle을 사용하여 dict을 저장하는 방법 (0) | 2021.06.14 |
Ubuntu에서 pip를 통해 python3 버전의 패키지를 설치하는 방법 (0) | 2021.06.09 |
Python에서 모든 객체 속성을 가져오는 방법 (0) | 2021.06.07 |
파이썬을 사용하여 CPU 수를 찾는 방법 (0) | 2021.06.03 |