source

두 문자열을 연결하기 위해 '+'를 사용하지 않을 이유가 있습니까?

lovecheck 2023. 7. 21. 21:43
반응형

두 문자열을 연결하기 위해 '+'를 사용하지 않을 이유가 있습니까?

파이썬의 일반적인 반대 패턴은 다음을 사용하여 문자열 시퀀스를 연결하는 것입니다.+고리 모양으로이것은 Python 인터프리터가 각 반복에 대해 새 문자열 개체를 만들어야 하고 결국 2차 시간이 소요되기 때문에 좋지 않습니다.(CPython의 최신 버전은 경우에 따라 이를 최적화할 수 있지만 다른 구현에서는 이를 최적화할 수 없으므로 프로그래머들은 이에 의존하는 것을 권장하지 않습니다.)''.join이것을 하는 올바른 방법입니다.

하지만 는 (여기 스택 오버플로 포함) 절대 사용해서는 안 된다고 들었습니다.+문자열 연결의 경우, 대신 항상 사용''.join또는 형식 문자열입니다.저는 당신이 두 개의 문자열만 연결하고 있다면 왜 이런 경우인지 이해할 수 없습니다.내 이해가 맞다면 2차 시간이 걸리지 않을 것이고, 나는 생각합니다.a + b둘 중 하나보다 더 깨끗하고 읽기 쉽습니다.''.join((a, b))또는'%s%s' % (a, b).

사용하는 것이 좋은 관행입니까?+두 줄을 연결하는 것?아니면 제가 모르는 문제가 있나요?

두 문자열을 연결하는 데 문제가 없습니다.+사실 그것은 읽기가 더 쉽습니다.''.join([a, b]).

두 개 이상의 문자열을 연결하는 것이 옳습니다.+(에 대한 O(n)와 비교하여) O(n^2) 연산입니다.join)로 인해 비효율적이 됩니다.그러나 이것은 루프를 사용하는 것과는 관련이 없습니다.심지어.a + b + c + ...각 연결이 새 문자열을 생성하기 때문에 O(n^2)입니다.

Cython 2.4 이상에서는 이를 완화하기 위해 노력하지만 여전히 사용하는 것이 좋습니다.join두 개 이상의 문자열을 연결할 때.

Plus 연산자는 두 개의 Python 문자열을 연결하는 완벽한 솔루션입니다.하지만 만약 여러분이 두 개 이상의 문자열(n > 25)을 계속 추가한다면, 여러분은 다른 것을 생각하고 싶을지도 모릅니다.

''.join([a, b, c])트릭은 성능 최적화입니다.

문자열 연결에 절대 +를 사용해서는 안 되며 대신 항상 '.join'을 사용해야 한다는 가정은 신화일 수 있습니다.를 사용하는 것은 사실입니다.+불변 문자열 개체의 불필요한 임시 복사본을 생성하지만 자주 인용되지 않는 다른 사실은 호출입니다.join루프에서 일반적으로 의 오버헤드를 추가합니다.function call예를 들어 보겠습니다.

두 개의 목록을 만듭니다. 하나는 연결된 SO 질문에서, 다른 하나는 더 큰 규모로 조작된 질문에서 작성합니다.

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

두가지기만들보다니겠습어을능,▁two▁functions다▁lets▁create니보를 만들어 보겠습니다.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을 사용하면 불필요한 함수 호출이 발생하여 오버헤드가 증가할 수 있습니다.

이제 다시 질문으로 돌아가겠습니다.▁of▁▁the▁one▁should▁discour.+1파운드가 join모든 경우에?

아니요, 상황을 고려해야 합니다.

  1. 문제의 문자열 길이
  2. 연결 작업의 수.

발달 전 최적화 과정에서 벗어난 것은 사악한 것입니다.

여러 사람과 함께 작업할 때, 정확히 무슨 일이 일어나고 있는지 알기가 어려울 때가 있습니다.연결 대신 형식 문자열을 사용하면 우리에게 수없이 발생한 특정 문제를 피할 수 있습니다.

예를 들어, 함수에는 인수가 필요하며 문자열을 얻을 것으로 예상하여 작성합니다.

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

그렇습니다: 포맷 문자열을 사용할 수 있다면 그렇게 하고 파이썬이 제공하는 기능을 활용하십시오.

Python 문서에 따르면 str.join()을 사용하면 다양한 Python 구현에서 성능 일관성을 얻을 수 있습니다.CPython이 s = s + t의 2차 동작을 최적화하지만 다른 Python 구현은 그렇지 않을 수 있습니다.

Cython 구현 세부 정보:s와 t가 모두 문자열인 경우 CPython과 같은 일부 Python 구현은 일반적으로 = s + t 또는 s += t 형식의 할당에 대해 인플레이스 최적화를 수행할 수 있습니다.적용 가능한 경우 이 최적화를 통해 2차 실행 시간의 가능성이 훨씬 낮아집니다.이 최적화는 버전과 구현에 따라 달라집니다.성능에 민감한 코드의 경우 버전 및 구현 간에 일관된 선형 연결 성능을 보장하는 str.join() 방법을 사용하는 것이 좋습니다.

Python 문서의 시퀀스 유형(각주[6] 참조)

빠른 테스트를 수행했습니다.

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) 시간을 나타내지 않습니다.

에서는 그서적어성능면는에서사, 용래도▁so▁using,.+괜찮습니다.

다음을 파이썬 3.8과 함께 사용합니다.

string4 = f'{string1}{string2}{string3}'

'.sys([a,b]) +보다 더 나은 해결책입니다.

Code는 Python의 다른 구현체(PyPy, Jython, IronPython, Cython, Psyco 등)에 불이익을 주지 않는 방식으로 작성되어야 하기 때문입니다.

a += b 또는 a = a + b는 CPython에서도 취약하며 refcounting 사용하지 않는 구현에서는 전혀 존재하지 않습니다(참조 카운팅은 객체, 메모리 블록, 디스크 공간 또는 기타 리소스와 같은 리소스에 대한 참조, 포인터 또는 핸들의 수를 저장하는 기술입니다).

https://www.python.org/dev/peps/pep-0008/ #프로그래밍 관련 정보

언급URL : https://stackoverflow.com/questions/10043636/any-reason-not-to-use-to-concatenate-two-strings

반응형