Nice programing

Java StringBuffer와 동등한 Python?

nicepro 2020. 11. 21. 09:19
반응형

Java StringBuffer와 동등한 Python?


Python에 Java와 같은 것이 StringBuffer있습니까? 문자열은 파이썬에서도 불변이므로 루프에서 편집하는 것은 비효율적입니다.


Python의 효율적인 문자열 연결 은 다소 오래된 기사이며,이 부분은 그 이후로 CPython에서 최적화 되었기 때문에 결합하는 것보다 순진한 연결이 훨씬 더 느리다는 주요 진술은 더 이상 유효하지 않습니다.

CPython 구현 세부 정보 : s와 t가 모두 문자열 인 경우 CPython과 같은 일부 Python 구현은 일반적으로 s = s + t 또는 s + = t 형식의 할당에 대해 내부 최적화를 수행 할 수 있습니다. 적용 가능한 경우이 최적화는 2 차 런타임을 훨씬 적게 만듭니다. 이 최적화는 버전 및 구현에 따라 다릅니다. 성능에 민감한 코드의 경우 버전 및 구현간에 일관된 선형 연결 성능을 보장하는 str.join () 메서드를 사용하는 것이 좋습니다. @ http://docs.python.org/2/library/stdtypes.html

나는 그들의 코드를 약간 수정했고 내 컴퓨터에서 다음과 같은 결과를 얻었습니다.

from cStringIO import StringIO
from UserString import MutableString
from array import array

import sys, timeit

def method1():
    out_str = ''
    for num in xrange(loop_count):
        out_str += `num`
    return out_str

def method2():
    out_str = MutableString()
    for num in xrange(loop_count):
        out_str += `num`
    return out_str

def method3():
    char_array = array('c')
    for num in xrange(loop_count):
        char_array.fromstring(`num`)
    return char_array.tostring()

def method4():
    str_list = []
    for num in xrange(loop_count):
        str_list.append(`num`)
    out_str = ''.join(str_list)
    return out_str

def method5():
    file_str = StringIO()
    for num in xrange(loop_count):
        file_str.write(`num`)
    out_str = file_str.getvalue()
    return out_str

def method6():
    out_str = ''.join([`num` for num in xrange(loop_count)])
    return out_str

def method7():
    out_str = ''.join(`num` for num in xrange(loop_count))
    return out_str


loop_count = 80000

print sys.version

print 'method1=', timeit.timeit(method1, number=10)
print 'method2=', timeit.timeit(method2, number=10)
print 'method3=', timeit.timeit(method3, number=10)
print 'method4=', timeit.timeit(method4, number=10)
print 'method5=', timeit.timeit(method5, number=10)
print 'method6=', timeit.timeit(method6, number=10)
print 'method7=', timeit.timeit(method7, number=10)

결과 :

2.7.1 (r271:86832, Jul 31 2011, 19:30:53) 
[GCC 4.2.1 (Based on Apple Inc. build 5658) (LLVM build 2335.15.00)]
method1= 0.171155929565
method2= 16.7158739567
method3= 0.420584917068
method4= 0.231794118881
method5= 0.323612928391
method6= 0.120429992676
method7= 0.145267963409

결론 :

  • join 여전히 concat을 이기지 만 약간
  • 목록 이해는 루프보다 빠릅니다 ( 목록을 만들 때 )
  • 생성기에 가입하는 것이 목록에 가입하는 것보다 느립니다.
  • 다른 방법은 쓸모가 없습니다 (특별한 작업을하지 않는 한)

무엇을하고 싶은지에 따라 다릅니다. 변경 가능한 시퀀스를 원하면 내장 list유형이 친구이며 str에서 목록으로 이동하는 것은 다음과 같이 간단합니다.

 mystring = "abcdef"
 mylist = list(mystring)
 mystring = "".join(mylist)

for 루프를 사용하여 큰 문자열을 만들고 싶다면, 파이썬적인 방법은 일반적으로 문자열 목록을 만든 다음 적절한 구분 기호 (줄 바꿈 등)와 함께 결합하는 것입니다.

그렇지 않으면 일부 텍스트 템플릿 시스템, 파서 또는 작업에 가장 적합한 특수 도구를 사용할 수도 있습니다.


아마도 bytearray를 사용하십시오 .

In [1]: s = bytearray('Hello World')

In [2]: s[:5] = 'Bye'

In [3]: s
Out[3]: bytearray(b'Bye World')

In [4]: str(s)
Out[4]: 'Bye World'

바이트 배열 사용의 매력은 메모리 효율성과 편리한 구문입니다. 임시 목록을 사용하는 것보다 빠를 수도 있습니다.

In [36]: %timeit s = list('Hello World'*1000); s[5500:6000] = 'Bye'; s = ''.join(s)
1000 loops, best of 3: 256 µs per loop

In [37]: %timeit s = bytearray('Hello World'*1000); s[5500:6000] = 'Bye'; str(s)
100000 loops, best of 3: 2.39 µs per loop

속도 차이의 대부분은 컨테이너 생성에 기인합니다.

In [32]: %timeit s = list('Hello World'*1000)
10000 loops, best of 3: 115 µs per loop

In [33]: %timeit s = bytearray('Hello World'*1000)
1000000 loops, best of 3: 1.13 µs per loop

이전에 제공된 답변이 거의 항상 가장 좋습니다. 그러나 때로는 문자열이 많은 메서드 호출 및 / 또는 루프에 걸쳐 만들어지기 때문에 줄 목록을 만든 다음 결합하는 것이 반드시 자연스러운 것은 아닙니다. 그리고 CPython을 사용하고 있거나 CPython의 최적화가 적용된다는 보장이 없기 때문에 또 다른 접근 방식은 print를 사용하는 것입니다!

다음은 헬퍼 클래스의 예입니다. 헬퍼 클래스는 사소하고 불필요하지만 접근 방식을 설명하는 역할을합니다 (Python 3).

import io

class StringBuilder(object):

  def __init__(self):
    self._stringio = io.StringIO()

  def __str__(self):
    return self._stringio.getvalue()

  def append(self, *objects, sep=' ', end=''):
    print(*objects, sep=sep, end=end, file=self._stringio)

sb = StringBuilder()
sb.append('a')
sb.append('b', end='\n')
sb.append('c', 'd', sep=',', end='\n')
print(sb)  # 'ab\nc,d\n'

이 링크는 파이썬에서 연결하는 데 유용 할 수 있습니다.

http://pythonadventures.wordpress.com/2010/09/27/stringbuilder/

위 링크의 예 :

def g():
    sb = []
    for i in range(30):
        sb.append("abcdefg"[i%7])

    return ''.join(sb)

print g()   

# abcdefgabcdefgabcdefgabcdefgab

"join"이 여전히 큰 승리를 보여주는 파이썬 3.6.2에서 실행 한 테스트입니다!

from time import time


def _with_format(i):
    _st = ''
    for i in range(0, i):
        _st = "{}{}".format(_st, "0")
    return _st


def _with_s(i):
    _st = ''
    for i in range(0, i):
        _st = "%s%s" % (_st, "0")
    return _st


def _with_list(i):
    l = []
    for i in range(0, i):
        l.append("0")
    return "".join(l)


def _count_time(name, i, func):
    start = time()
    r = func(i)
    total = time() - start
    print("%s done in %ss" % (name, total))
    return r

iterationCount = 1000000

r1 = _count_time("with format", iterationCount, _with_format)
r2 = _count_time("with s", iterationCount, _with_s)
r3 = _count_time("with list and join", iterationCount, _with_list)

if r1 != r2 or r2 != r3:
    print("Not all results are the same!")

결과는 다음과 같습니다.

with format done in 17.991968870162964s
with s done in 18.36879801750183s
with list and join done in 0.12142801284790039s

I've added to Roee Gavirel's code 2 additional tests that show conclusively that joining lists into strings is not any faster than s += "something".

Results:

Python 2.7.15rc1    

Iterations: 100000
format    done in 0.317540168762s
%s        done in 0.151262044907s
list+join done in 0.0055148601532s
str cat   done in 0.00391721725464s

Python 3.6.7

Iterations: 100000
format    done in 0.35594654083251953s
%s        done in 0.2868080139160156s
list+join done in 0.005924701690673828s
str cat   done in 0.0054128170013427734s
f str     done in 0.12870001792907715s

Code:

from time import time


def _with_cat(i):
    _st = ''
    for i in range(0, i):
        _st += "0"
    return _st


def _with_f_str(i):
    _st = ''
    for i in range(0, i):
        _st = f"{_st}0"
    return _st


def _with_format(i):
    _st = ''
    for i in range(0, i):
        _st = "{}{}".format(_st, "0")
    return _st


def _with_s(i):
    _st = ''
    for i in range(0, i):
        _st = "%s%s" % (_st, "0")
    return _st


def _with_list(i):
    l = []
    for i in range(0, i):
        l.append("0")
    return "".join(l)


def _count_time(name, i, func):
    start = time()
    r = func(i)
    total = time() - start
    print("%s done in %ss" % (name, total))
    return r


iteration_count = 100000

print('Iterations: {}'.format(iteration_count))
r1 = _count_time("format   ", iteration_count, _with_format)
r2 = _count_time("%s       ", iteration_count, _with_s)
r3 = _count_time("list+join", iteration_count, _with_list)
r4 = _count_time("str cat  ", iteration_count, _with_cat)
r5 = _count_time("f str    ", iteration_count, _with_f_str)

if len(set([r1, r2, r3, r4, r5])) != 1:
    print("Not all results are the same!")

참고URL : https://stackoverflow.com/questions/19926089/python-equivalent-of-java-stringbuffer

반응형

'Nice programing' 카테고리의 다른 글

.htaccess를 통해 http에서 https로  (0) 2020.11.22
Magit 단일 파일 되돌리기  (0) 2020.11.21
도커 컨테이너 SSL 인증서  (0) 2020.11.21
WPF의 숫자 데이터 입력  (0) 2020.11.21
C #의 큰 정수  (0) 2020.11.21