파이썬에서 가장 효율적인 문자열 연결 방법은 무엇입니까?
Python에 효율적인 대량 문자열 연결 방법이 있습니까(C#의 StringBuilder 또는 Java의 StringBuffer)?
여기서 다음 방법을 찾았습니다.
- 다을사용간연결을 사용한
+
- 및 "" " " 를 합니다.
join
방법 - 용사를 합니다.
UserString
MutableString
컨트롤 모듈 - 및 문배열및용사를
array
컨트롤 모듈 - 용사를 합니다.
cStringIO
StringIO
컨트롤 모듈
무엇을 사용해야 하며 그 이유는 무엇입니까?
다음과 같은 이점에 관심이 있을 것입니다.Guido의 최적화 일화입니다.비록 이것이 오래된 기사이고 같은 것들의 존재보다 앞선다는 것도 기억할 가치가 있습니다.''.join
생각엔)string.joinfields
거의 동일함)
그 힘에 힘입어,array
당신이 당신의 문제를 그것에 슈혼할 수 있다면 모듈이 가장 빠를 수 있습니다.그렇지만''.join
충분히 빠르며 관용적이어서 다른 파이썬 프로그래머들이 이해하기 쉽다는 장점이 있습니다.
마지막으로, 최적화의 황금률입니다. 필요하다는 것을 알지 못하면 최적화하지 말고, 추측하기보다는 측정하십시오.
모듈을 사용하여 다양한 방법을 측정할 수 있습니다.인터넷에서 모르는 사람들이 추측하는 것 대신에, 그것은 당신에게 어떤 것이 가장 빠른지 알려줄 수 있습니다.
모든 구성 요소를 미리 알고 있는 경우 Python 3.6에 도입된 -strings 또는 형식화된 문자열이라고도 하는 리터럴 문자열 보간을 사용합니다.
Mkoistinen의 답변에서 나온 테스트 케이스를 고려할 때, 문자열이 있습니다.
domain = 'some_really_long_example.com'
lang = 'en'
path = 'some/really/long/path/'
리눅스에서 Python 3.6을 사용하는 내 컴퓨터의 경쟁자들과 그들의 실행 시간은 IPython에 의해 시간이 지정되고 그것의 모듈 시간은
f'http://{domain}/{lang}/{path}'
0.304파운드'http://%s/%s/%s' % (domain, lang, path)
.321µs'http://' + domain + '/' + lang + '/' + path
.356µs''.join(('http://', domain, '/', lang, '/', path))
0.249µs(일정한 길이의 튜플을 작성하는 것이 일정한 길이의 목록을 작성하는 것보다 약간 빠름).
따라서 가능한 가장 짧고 가장 아름다운 코드도 가장 빠릅니다.
2의 2와 될 수 .+
8비트 문자열의 경우 0.203µs가 필요하며, 문자열이 모두 유니코드인 경우 0.259µs가 필요합니다.
3에서는 (Python 3.6 버전)의 f''
문자열은 가능한 가장 느렸습니다 - 실제로 생성된 바이트 코드는 거의 동일합니다.''.join()
필요한호있는사례출에 불필요한 경우str.__format__
논쟁 없이 그냥 돌아올 것입니다.self
은 3final 되었습니다.)이러한 비효율성은 3.6 기말고사 전에 해결되었습니다.)
''.join(sequence_of_strings)
일반적으로 가장 간편하고 빠르게 작동합니다.
당신이 무엇을 하느냐에 따라 다릅니다.
Python 2.5 이후에는 + 연산자와의 문자열 연결이 매우 빠릅니다.몇 개의 값을 연결하는 경우 + 연산자를 사용하는 것이 가장 좋습니다.
>>> x = timeit.Timer(stmt="'a' + 'b'")
>>> x.timeit()
0.039999961853027344
>>> x = timeit.Timer(stmt="''.join(['a', 'b'])")
>>> x.timeit()
0.76200008392333984
그러나 문자열을 루프에 결합하는 경우에는 목록 결합 방법을 사용하는 것이 좋습니다.
>>> join_stmt = """
... joined_str = ''
... for i in xrange(100000):
... joined_str += str(i)
... """
>>> x = timeit.Timer(join_stmt)
>>> x.timeit(100)
13.278000116348267
>>> list_stmt = """
... str_list = []
... for i in xrange(100000):
... str_list.append(str(i))
... ''.join(str_list)
... """
>>> x = timeit.Timer(list_stmt)
>>> x.timeit(100)
12.401000022888184
...하지만 차이가 눈에 띄기 전에 비교적 많은 수의 문자열을 조합해야 합니다.
John Fouhy의 대답에 따르면, 꼭 필요한 경우가 아니라면 최적화하지 마십시오. 하지만 만약 여러분이 여기에 와서 이 질문을 한다면, 그것은 바로 여러분이 해야 하기 때문일 것입니다.
저 같은 경우에는 문자열 변수에서 몇 개의 URL을 조합해야 했습니다.빨리. 나는 (지금까지) 아무도 문자열 형식 방법을 고려하지 않는 것을 알아차렸고, 그래서 나는 그것을 시도해 볼 생각이었고, 대부분의 가벼운 관심을 위해, 나는 좋은 측정을 위해 문자열 보간 연산자를 거기에 던져야겠다고 생각했습니다.
솔직히, 저는 이것들 중 어느 것도 직접적인 '+' 연산이나 '.join()'까지 쌓일 것이라고 생각하지 않았습니다.근데 그거 알아요?내 Python 2.7.5 시스템에서는 문자열 보간 연산자가 모든 문자열과 문자열을 제어합니다.format()는 최악의 성능입니다.
# concatenate_test.py
from __future__ import print_function
import timeit
domain = 'some_really_long_example.com'
lang = 'en'
path = 'some/really/long/path/'
iterations = 1000000
def meth_plus():
'''Using + operator'''
return 'http://' + domain + '/' + lang + '/' + path
def meth_join():
'''Using ''.join()'''
return ''.join(['http://', domain, '/', lang, '/', path])
def meth_form():
'''Using string.format'''
return 'http://{0}/{1}/{2}'.format(domain, lang, path)
def meth_intp():
'''Using string interpolation'''
return 'http://%s/%s/%s' % (domain, lang, path)
plus = timeit.Timer(stmt="meth_plus()", setup="from __main__ import meth_plus")
join = timeit.Timer(stmt="meth_join()", setup="from __main__ import meth_join")
form = timeit.Timer(stmt="meth_form()", setup="from __main__ import meth_form")
intp = timeit.Timer(stmt="meth_intp()", setup="from __main__ import meth_intp")
plus.val = plus.timeit(iterations)
join.val = join.timeit(iterations)
form.val = form.timeit(iterations)
intp.val = intp.timeit(iterations)
min_val = min([plus.val, join.val, form.val, intp.val])
print('plus %0.12f (%0.2f%% as fast)' % (plus.val, (100 * min_val / plus.val), ))
print('join %0.12f (%0.2f%% as fast)' % (join.val, (100 * min_val / join.val), ))
print('form %0.12f (%0.2f%% as fast)' % (form.val, (100 * min_val / form.val), ))
print('intp %0.12f (%0.2f%% as fast)' % (intp.val, (100 * min_val / intp.val), ))
결과:
# Python 2.7 concatenate_test.py
plus 0.360787868500 (90.81% as fast)
join 0.452811956406 (72.36% as fast)
form 0.502608060837 (65.19% as fast)
intp 0.327636957169 (100.00% as fast)
더 짧은 도메인과 더 짧은 경로를 사용해도 보간은 여전히 승리합니다.그러나 문자열이 길수록 그 차이는 더 뚜렷합니다.
이제 좋은 테스트 스크립트를 얻었기 때문에 Python 2.6, 3.3 및 3.4로 테스트를 수행했습니다. 결과는 다음과 같습니다.파이썬 2.6에서는 플러스 연산자가 가장 빠릅니다!파이썬 3에서 조인이 승리합니다.참고: 이러한 테스트는 내 시스템에서 매우 반복 가능합니다.따라서 Python 3.x에서는 'plus'가 항상 빠릅니다. 2.6에서는 'intp'가 항상 빠르며, Python 3.x에서는 'join'이 항상 빠릅니다.
# Python 2.6 concatenate_test.py
plus 0.338213920593 (100.00% as fast)
join 0.427221059799 (79.17% as fast)
form 0.515371084213 (65.63% as fast)
intp 0.378169059753 (89.43% as fast)
# Python 3.3 concatenate_test.py
plus 0.409130576998 (89.20% as fast)
join 0.364938726001 (100.00% as fast)
form 0.621366866995 (58.73% as fast)
intp 0.419064424001 (87.08% as fast)
# Python 3.4 concatenate_test.py
plus 0.481188605998 (85.14% as fast)
join 0.409673971997 (100.00% as fast)
form 0.652010936996 (62.83% as fast)
intp 0.460400978001 (88.98% as fast)
# Python 3.5 concatenate_test.py
plus 0.417167026084 (93.47% as fast)
join 0.389929617057 (100.00% as fast)
form 0.595661019906 (65.46% as fast)
intp 0.404455224983 (96.41% as fast)
배운 교훈:
- 가끔은 제 추측이 완전히 틀릴 때도 있습니다.
- 시스템 환경에 대해 테스트합니다.운영 환경에서 운영하게 될 것입니다.
- 문자열 보간이 아직 완료되지 않았습니다!
tl;dr:
- Python 2.6을 사용하는 경우 '+' 연산자를 사용합니다.
- Python 2.7을 사용하는 경우 '%' 연산자를 사용합니다.
- Python 3.x를 사용하는 경우 '.join()을 사용합니다.
연결할 때마다 새 문자열의 상대적 크기에 따라 크게 달라집니다.
과 +
연산자, 모든 연결에 대해 새 문자열이 만들어집니다., 중문자상로길면으적대이,+
새 중간 문자열이 저장되고 있기 때문에 속도가 점점 느려집니다.
이 경우를 고려해 보십시오.
from time import time
stri=''
a='aagsdfghfhdyjddtyjdhmfghmfgsdgsdfgsdfsdfsdfsdfsdfsdfddsksarigqeirnvgsdfsdgfsdfgfg'
l=[]
# Case 1
t=time()
for i in range(1000):
stri=stri+a+repr(i)
print time()-t
# Case 2
t=time()
for i in xrange(1000):
l.append(a+repr(i))
z=''.join(l)
print time()-t
# Case 3
t=time()
for i in range(1000):
stri=stri+repr(i)
print time()-t
# Case 4
t=time()
for i in xrange(1000):
l.append(repr(i))
z=''.join(l)
print time()-t
결과.
1 0.00493192672729
2 0.000509023666382
3 0.00042200088501
4 0.000482797622681
1&2의 경우 큰 문자열을 추가하고 join()이 약 10배 더 빠르게 수행됩니다.3&4의 경우 작은 문자열을 추가하고 '+'가 약간 더 빨리 수행됩니다.
업데이트: Python 3.11에는 % 포맷에 대한 몇 가지 최적화가 있지만 f-string을 고수하는 것이 더 나을 수 있습니다.
Python 3.8.6/3.9의 경우 perfplot에서 오류가 발생했기 때문에 더티 해킹을 해야 했습니다.여기서 을 가정합니다.x[0]
입니다.a
그리고.x[1]
이라b
:
큰 데이터의 경우 그림이 거의 같습니다.작은 데이터의 경우
이것은 코드, 큰 데이터 == 범위(8), 작은 데이터 == 범위(4)입니다.
import perfplot
from random import choice
from string import ascii_lowercase as letters
def generate_random(x):
data = ''.join(choice(letters) for i in range(x))
sata = ''.join(choice(letters) for i in range(x))
return [data,sata]
def fstring_func(x):
return [ord(i) for i in f'{x[0]}{x[1]}']
def format_func(x):
return [ord(i) for i in "{}{}".format(x[0], x[1])]
def replace_func(x):
return [ord(i) for i in "|~".replace('|', x[0]).replace('~', x[1])]
def join_func(x):
return [ord(i) for i in "".join([x[0], x[1]])]
perfplot.show(
setup=lambda n: generate_random(n),
kernels=[
fstring_func,
format_func,
replace_func,
join_func,
],
n_range=[int(k ** 2.5) for k in range(4)],
)
중간 데이터가 있고 네 개의 문자열이 있는 경우x[0]
,x[1]
,x[2]
,x[3]
: 문자열대신두":
def generate_random(x):
a = ''.join(choice(letters) for i in range(x))
b = ''.join(choice(letters) for i in range(x))
c = ''.join(choice(letters) for i in range(x))
d = ''.join(choice(letters) for i in range(x))
return [a,b,c,d]
f-string을 고수하는 것이 좋습니다.또한 %s의 속도는 .format()과 비슷합니다.
크기를 알 수 없는 추가 가능한 문자열이 필요한 상황에 부딪혔습니다.벤치마크 결과는 다음과 같습니다(파이썬 2.7.3).
$ python -m timeit -s 's=""' 's+="a"'
10000000 loops, best of 3: 0.176 usec per loop
$ python -m timeit -s 's=[]' 's.append("a")'
10000000 loops, best of 3: 0.196 usec per loop
$ python -m timeit -s 's=""' 's="".join((s,"a"))'
100000 loops, best of 3: 16.9 usec per loop
$ python -m timeit -s 's=""' 's="%s%s"%(s,"a")'
100000 loops, best of 3: 19.4 usec per loop
이것은 '+='이 가장 빠르다는 것을 보여주는 것 같습니다.스카이마인드 링크의 결과는 약간 구식입니다.
(두 번째 예는 완전하지 않다는 것을 알고 있습니다.최종 목록에 참여해야 합니다.그러나 이것은 단순히 목록을 준비하는 것이 문자열 연결보다 더 오래 걸린다는 것을 보여줍니다.)
1년 후, Mkoistinen의 답변을 Python 3.4.3으로 테스트해 보겠습니다.
- + 0.963564149000(95.83% 빠른 속도)
- 0.923408469000(100.00% 빠른 속도)에 가입합니다.
- 폼 1.501130934000(61.51% 빠른 속도)
- intp 1.019677452000(90.56% 빠른 속도)
변한 게 없습니다.조인은 여전히 가장 빠른 방법입니다.가독성 측면에서 문자열 보간(intp)이 가장 좋은 선택인 경우에도 문자열 보간을 사용할 수 있습니다.
아마도 "Python 3.6의 새로운 f-strings"가 문자열을 연결하는 가장 효율적인 방법일 것입니다.
%s 사용
>>> timeit.timeit("""name = "Some"
... age = 100
... '%s is %s.' % (name, age)""", number = 10000)
0.0029734770068898797
.format 사용
>>> timeit.timeit("""name = "Some"
... age = 100
... '{} is {}.'.format(name, age)""", number = 10000)
0.004015227983472869
f-string 사용
>>> timeit.timeit("""name = "Some"
... age = 100
... f'{name} is {age}.'""", number = 10000)
0.0019175919878762215
짧은 문자열의 작은 집합(예: 몇 자 이하의 문자열 2개 또는 3개)의 경우 더하기가 여전히 훨씬 빠릅니다.파이썬 2와 3에서 mkoistinen의 멋진 스크립트 사용하기:
plus 2.679107467004 (100.00% as fast)
join 3.653773699996 (73.32% as fast)
form 6.594011374000 (40.63% as fast)
intp 4.568015249999 (58.65% as fast)
따라서 코드가 많은 수의 개별적인 작은 연결을 수행할 때 속도가 중요한 경우 선호되는 방법입니다.
Jason Baker의 벤치마크에서 영감을 받아 10가지를 비교한 간단한 벤치마크를 소개합니다."abcdefghijklmnopqrstuvxyz"
문자열, 표시.join()
더 빠릅니다. 이렇게 작은 변수가 증가하더라도 다음과 같습니다.
연결
>>> x = timeit.Timer(stmt='"abcdefghijklmnopqrstuvxyz" + "abcdefghijklmnopqrstuvxyz" + "abcdefghijklmnopqrstuvxyz" + "abcdefghijklmnopqrstuvxyz" + "abcdefghijklmnopqrstuvxyz" + "abcdefghijklmnopqrstuvxyz" + "abcdefghijklmnopqrstuvxyz" + "abcdefghijklmnopqrstuvxyz" + "abcdefghijklmnopqrstuvxyz" + "abcdefghijklmnopqrstuvxyz" + "abcdefghijklmnopqrstuvxyz"')
>>> x.timeit()
0.9828147209324385
합류하다
>>> x = timeit.Timer(stmt='"".join(["abcdefghijklmnopqrstuvxyz", "abcdefghijklmnopqrstuvxyz", "abcdefghijklmnopqrstuvxyz", "abcdefghijklmnopqrstuvxyz", "abcdefghijklmnopqrstuvxyz", "abcdefghijklmnopqrstuvxyz", "abcdefghijklmnopqrstuvxyz", "abcdefghijklmnopqrstuvxyz", "abcdefghijklmnopqrstuvxyz", "abcdefghijklmnopqrstuvxyz", "abcdefghijklmnopqrstuvxyz"])')
>>> x.timeit()
0.6114138159765048
언급URL : https://stackoverflow.com/questions/1316887/what-is-the-most-efficient-string-concatenation-method-in-python
'programing' 카테고리의 다른 글
DistutilsOptionError: home 또는 prefix/exec-prefix 중 하나를 제공해야 합니다. 둘 다 제공하지 않습니다. (0) | 2023.07.16 |
---|---|
파일이 유효한 이미지 파일인지 확인하는 방법은 무엇입니까? (0) | 2023.07.16 |
MongoDb Atlas 서버에 연결하는 중 오류 발생 (0) | 2023.07.06 |
정적 인라인, 외부 인라인 및 일반 인라인 기능의 차이점은 무엇입니까? (0) | 2023.07.06 |
특정 값을 가진 Mongoose 스키마 속성 (0) | 2023.07.06 |