¿Clase de cadena de Python como StringBuilder en C#?

6 minutos de lectura

avatar de usuario
icono

¿Hay alguna clase de cadena en Python como StringBuilder Cía#?

  • Este es un duplicado del equivalente Python de Java StringBuffer. PRECAUCIÓN: Las respuestas aquí están muy desactualizadas y, de hecho, se han vuelto engañosas. Consulte esa otra pregunta para obtener respuestas que son más relevantes para las versiones modernas de Python (ciertamente 2.7 y superiores).

    – Jean-François Corbett

    20 de noviembre de 2017 a las 8:52


avatar de usuario
Andrés Liebre

No hay una correlación uno a uno. Para un artículo realmente bueno por favor vea Concatenación eficiente de cadenas en Python:

La construcción de cadenas largas en el lenguaje de programación Python a veces puede resultar en un código de ejecución muy lento. En este artículo investigo el rendimiento computacional de varios métodos de concatenación de cadenas.

TLDR el método más rápido está a continuación. Es extremadamente compacto, y también bastante comprensible:

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

  • Tenga en cuenta que este artículo fue escrito en base a Python 2.2. Es probable que las pruebas resulten algo diferentes en una versión moderna de Python (CPython generalmente optimiza con éxito la concatenación, pero no desea depender de esto en código importante) y una expresión de generador donde usa una comprensión de lista sería digna de consideración .

    –Mike Graham

    10 de marzo de 2010 a las 6:35


  • Sería bueno incluir algunos aspectos destacados en ese artículo, al menos un par de implementaciones (para evitar problemas de enlaces rotos).

    – jpmc26

    29 de julio de 2014 a las 22:22

  • Método 1: resultString += appendString es el más rápido según las pruebas de @Antoine-tran a continuación

    – Tal como

    31 de diciembre de 2015 a las 17:47

  • Su cita no responde en absoluto a la pregunta. Incluya las partes relevantes en su propia respuesta, para cumplir con las nuevas pautas.

    – Nic

    21 oct 2016 a las 16:48

Confiar en las optimizaciones del compilador es frágil. No se puede confiar en los puntos de referencia vinculados en la respuesta aceptada y los números proporcionados por Antoine-tran. Andrew Hare comete el error de incluir una llamada a repr en sus métodos. Eso ralentiza todos los métodos por igual pero oscurece la pena real en la construcción de la cadena.

Usar join. Es muy rápido y más robusto.

$ ipython3
Python 3.5.1 (default, Mar  2 2016, 03:38:02) 
IPython 4.1.2 -- An enhanced Interactive Python.

In [1]: values = [str(num) for num in range(int(1e3))]

In [2]: %%timeit
   ...: ''.join(values)
   ...: 
100000 loops, best of 3: 7.37 µs per loop

In [3]: %%timeit
   ...: result=""
   ...: for value in values:
   ...:     result += value
   ...: 
10000 loops, best of 3: 82.8 µs per loop

In [4]: import io

In [5]: %%timeit
   ...: writer = io.StringIO()
   ...: for value in values:
   ...:     writer.write(value)
   ...: writer.getvalue()
   ...: 
10000 loops, best of 3: 81.8 µs per loop

  • Sí el repr call domina el tiempo de ejecución, pero no hay necesidad de hacer el error personal.

    – Alex Reining

    17 de agosto de 2018 a las 21:43

  • @AlexReinking lo siento, no significa nada personal. No estoy seguro de qué te hizo pensar que era personal. Pero si fue el uso de sus nombres, los usé solo para referirme a las respuestas del usuario (coincide con los nombres de usuario, no estoy seguro de si hay una mejor manera).

    – GrantJ

    18 de agosto de 2018 a las 19:15

  • buen ejemplo de sincronización que separa las operaciones de inicialización y concatenación de datos

    – aiodintsov

    29 de junio de 2019 a las 22:37

He usado el código de Oliver Crow (enlace proporcionado por Andrew Hare) y lo he adaptado un poco para personalizar Python 2.7.3. (usando el paquete timeit). Corrí en mi computadora personal, Lenovo T61, 6 GB de RAM, Debian GNU/Linux 6.0.6 (squeeze).

Aquí está el resultado de 10.000 iteraciones:

method1:  0.0538418292999 secs
process size 4800 kb
method2:  0.22602891922 secs
process size 4960 kb
method3:  0.0605459213257 secs
process size 4980 kb
method4:  0.0544030666351 secs
process size 5536 kb
method5:  0.0551080703735 secs
process size 5272 kb
method6:  0.0542731285095 secs
process size 5512 kb

y para 5,000,000 de iteraciones (se ignoró el método 2 porque funcionó demasiado lento, como una eternidad):

method1:  5.88603997231 secs
process size 37976 kb
method3:  8.40748500824 secs
process size 38024 kb
method4:  7.96380496025 secs
process size 321968 kb
method5:  8.03666186333 secs
process size 71720 kb
method6:  6.68192911148 secs
process size 38240 kb

Es bastante obvio que los chicos de Python han hecho un gran trabajo para optimizar la concatenación de cadenas y, como dijo Hoare: “la optimización prematura es la raíz de todos los males” 🙂

  • Aparentemente, Hoare no acepta que: hans.gerwitz.com/2004/08/12/…

    – Pimín Konstantin Kefaloukos

    11 de diciembre de 2012 a las 13:13


  • No es una optimización prematura para evitar optimizaciones frágiles y dependientes del intérprete. Si alguna vez desea migrar a PyPy o arriesgarse a encontrar uno de los muchos casos de fallas sutiles para la optimización, haga las cosas de la manera correcta.

    – Veedrac

    3 de noviembre de 2014 a las 21:46

  • Parece que el Método 1 es más fácil de optimizar para el compilador.

    – bombomb007

    29 de abril de 2015 a las 18:21

avatar de usuario
mike graham

Python tiene varias cosas que cumplen propósitos similares:

  • Una forma común de construir cadenas grandes a partir de piezas es hacer crecer una lista de cadenas y unirlas cuando haya terminado. Este es un modismo de Python de uso frecuente.
    • Para crear cadenas que incorporen datos con formato, haría el formato por separado.
  • Para la inserción y eliminación a nivel de carácter, mantendría una lista de cadenas de longitud uno. (Para hacer esto a partir de una cadena, llamarías list(your_string). También podrías usar un UserString.MutableString para esto.
  • (c)StringIO.StringIO es útil para cosas que de otro modo tomarían un archivo, pero menos para la construcción general de cadenas.

Usando el método 5 de arriba (The Pseudo File) podemos obtener muy buen rendimiento y flexibilidad

from cStringIO import StringIO

class StringBuilder:
     _file_str = None

     def __init__(self):
         self._file_str = StringIO()

     def Append(self, str):
         self._file_str.write(str)

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

ahora usándolo

sb = StringBuilder()

sb.Append("Hello\n")
sb.Append("World")

print sb

avatar de usuario
dominic k

puedes probar cadenaIO o cStringIO

avatar de usuario
Cerebro

No hay un análogo explícito: creo que se espera que use concatenaciones de cadenas (probablemente optimizadas como se dijo antes) o una clase de terceros (dudo que sean mucho más eficientes: las listas en python son de tipo dinámico, por lo que no funcionan rápido) carbonizarse[] para el búfer como supongo). Las clases similares a Stringbuilder no son una optimización prematura debido a la característica innata de las cadenas en muchos idiomas (inmutabilidad), que permite muchas optimizaciones (por ejemplo, hacer referencia al mismo búfer para segmentos/subcadenas). Las clases similares a Stringbuilder/stringbuffer/stringstream funcionan mucho más rápido que concatenar cadenas (produciendo muchos objetos temporales pequeños que aún necesitan asignaciones y recolección de basura) e incluso herramientas de formato de cadena similares a printf, sin necesidad de interpretar la sobrecarga del patrón de formato que consume bastante para muchas llamadas de formato.

¿Ha sido útil esta solución?