java python stringbuffer

Python equivalente a Java StringBuffer?



(6)

¡Solo una prueba que ejecuto en Python 3.6.2 que muestra que "join" todavía gana GRANDE!

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!")

Y la salida fue:

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

¿Hay algo en Python como StringBuffer de Java? Dado que las cadenas también son inmutables en Python, editarlas en bucles sería ineficiente.


Depende de lo que quieras hacer. Si desea una secuencia mutable, el tipo de list integrada es su amigo, y pasar de str a list y volver es tan simple como:

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

Si desea construir una cadena grande usando un bucle for, la forma pythonic suele ser construir una lista de cadenas y unirlas con el separador adecuado (linebreak o lo que sea).

De lo contrario, también puede usar algún sistema de plantilla de texto, un analizador o cualquier herramienta especializada que sea la más adecuada para el trabajo.


Las respuestas proporcionadas anteriormente son casi siempre las mejores. Sin embargo, a veces la cadena se crea a través de muchas llamadas a métodos y / o bucles, por lo que no es necesariamente natural crear una lista de líneas y luego unirlas. Y como no hay garantía de que esté utilizando CPython o de que se aplique la optimización de CPython, ¡entonces otro enfoque es simplemente usar print!

Aquí hay un ejemplo de clase de ayuda, aunque la clase de ayuda es trivial y probablemente innecesaria, sirve para ilustrar el enfoque (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''


Tal vez use un 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''

El atractivo de usar un bytearray es su eficiencia de memoria y su conveniente sintaxis. También puede ser más rápido que usar una lista temporal:

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

Tenga en cuenta que gran parte de la diferencia de velocidad se debe a la creación del contenedor:

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



Efficient String Concatenation en Python es un artículo bastante antiguo y su afirmación principal de que la concatenación ingenua es mucho más lenta que la unión ya no es válida, porque esta parte se ha optimizado en CPython desde entonces:

Detalle de implementación de CPython: si s y t son cadenas, algunas implementaciones de Python como CPython generalmente pueden realizar una optimización in situ para asignaciones de la forma s = s + t o s + = t. Cuando corresponda, esta optimización hace que el tiempo de ejecución cuadrático sea mucho menos probable. Esta optimización depende tanto de la versión como de la implementación. Para el código sensible al rendimiento, es preferible utilizar el método str.join () que asegura un rendimiento de concatenación lineal consistente en las versiones y las implementaciones. @ http://docs.python.org/2/library/stdtypes.html

He adaptado un poco su código y obtuve los siguientes resultados en mi máquina:

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)

Resultados:

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

Conclusiones

  • join aún gana sobre concat, pero marginalmente
  • las listas de comprensión son más rápidas que los bucles
  • unir generadores es más lento que unir listas
  • otros métodos son inútiles (a menos que esté haciendo algo especial)