Classe de string Python como StringBuilder em C #?

121

Existe alguma classe de string em Python como StringBuilderem C #?

icn
fonte
6
Esta é uma duplicata do equivalente em Python de Java StringBuffer . CUIDADO: As respostas aqui estão muito desatualizadas e, na verdade, tornaram-se enganosas. Veja essa outra pergunta para respostas que são mais relevantes para as versões modernas do Python (certamente 2.7 e acima).
Jean-François Corbett

Respostas:

102

Não há correlação um a um. Para um artigo realmente bom, consulte Concatenação eficiente de strings em Python :

Construir strings longas na linguagem de programação Python às vezes pode resultar em um código de execução muito lento. Neste artigo, investigo o desempenho computacional de vários métodos de concatenação de strings.

Andrew Hare
fonte
27
Observe que este artigo foi escrito com base no Python 2.2. Os testes provavelmente seriam um pouco diferentes em uma versão moderna do Python (o CPython geralmente otimiza com sucesso a concatenação, mas você não quer depender disso em códigos importantes) e uma expressão geradora onde ele usa uma compreensão de lista seria digna de consideração .
Mike Graham
4
Seria bom trazer alguns destaques nesse artigo, pelo menos algumas das implementações (para evitar problemas de podridão de link).
jpmc26
3
Método 1: resultString + = appendString é o mais rápido de acordo com os testes de @ Antoine-tran abaixo
Justas
5
Sua citação não responde de forma alguma à pergunta. Inclua as partes relevantes em sua própria resposta, para cumprir as novas diretrizes.
Processo de Fundo Monica em
27

Usei o código de Oliver Crow (link fornecido por Andrew Hare) e adaptei-o um pouco para ajustar o Python 2.7.3. (usando o pacote timeit). Eu executei em meu computador pessoal, Lenovo T61, 6GB de RAM, Debian GNU / Linux 6.0.6 (squeeze).

Aqui está o resultado para 10.000 iterações:

método1: 0,0538418292999 s
tamanho do processo 4800 kb
método 2: 0,22602891922 s
tamanho do processo 4960 kb
método 3: 0,0605459213257 s
tamanho do processo 4980 kb
método 4: 0,0544030666351 s
tamanho do processo 5536 kb
método 5: 0,0551080703735 s
tamanho do processo 5272 kb
método 6: 0,0542731285095 s
tamanho do processo 5512 kb

e para 5.000.000 de iterações (o método 2 foi ignorado porque foi executado muito lentamente, como para sempre):

método 1: 5,88603997231 s
tamanho do processo 37976 kb
método 3: 8,40748500824 s
tamanho do processo 38024 kb
método 4: 7,96380496025 segs
tamanho do processo 321968 kb
método 5: 8,03666186333 s
tamanho do processo 71720 kb
método 6: 6,68192911148 s
tamanho do processo 38240 kb

É bastante óbvio que os caras do Python fizeram um ótimo trabalho para otimizar a concatenação de strings e, como Hoare disse: "a otimização prematura é a raiz de todos os males" :-)

Antoine-tran
fonte
2
Aparentemente Hoare não aceita isso: hans.gerwitz.com/2004/08/12/…
Pimin Konstantin Kefaloukos
5
Não é uma otimização prematura evitar otimizações frágeis e dependentes do interpretador. Se você quiser portar para PyPy ou correr o risco de encontrar um dos muitos casos de falha sutis para a otimização, faça as coisas da maneira certa.
Veedrac
1
Parece que o Método 1 é mais fácil para o compilador otimizar.
mbomb007
25

Depender de otimizações do compilador é frágil. Os benchmarks vinculados na resposta aceita e os números fornecidos pela Antoine-tran não são confiáveis. Andrew Hare comete o erro de incluir uma chamada para reprem seus métodos. Isso retarda todos os métodos igualmente, mas obscurece a verdadeira penalidade na construção da string.

Use join. É muito rápido e mais 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
GrantJ
fonte
Sim, a reprchamada domina o tempo de execução, mas não há necessidade de tornar o erro pessoal.
Alex Reinking de
3
@AlexReinking, desculpe, nada de pessoal significava. Não sei o que o fez pensar que era pessoal. Mas se fosse o uso de seus nomes, usei-os apenas para me referir às respostas do usuário (corresponde a nomes de usuários, não tenho certeza se existe uma maneira melhor).
GrantJ
1
exemplo de bom tempo que separa as operações de inicialização e concatenação de dados
aiodintsov
19

Python tem várias coisas que atendem a propósitos semelhantes:

  • Uma maneira comum de construir cordas grandes a partir de pedaços é aumentar uma lista de cordas e juntá-la quando terminar. Este é um idioma Python usado com freqüência.
    • Para construir strings que incorporam dados com formatação, você faria a formatação separadamente.
  • Para inserção e exclusão em um nível de caractere, você manteria uma lista de strings de comprimento um. (Para fazer isso a partir de uma string, você chamaria list(your_string). Você também pode usar um UserString.MutableStringpara isso.
  • (c)StringIO.StringIO é útil para coisas que de outra forma levariam um arquivo, mas nem tanto para a construção geral de strings.
Mike Graham
fonte
10

Usando o método 5 acima (O Pseudo Arquivo), podemos obter um desempenho e flexibilidade muito bons

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()

agora usando

sb = StringBuilder()

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

print sb
Thomas Watson
fonte
4

você pode tentar StringIO ou cStringIO

ghostdog74
fonte
-1

Não há analogia explícita - acho que se espera que você use concatenações de string (provavelmente otimizadas como dito antes) ou classe de terceiros (duvido que sejam muito mais eficientes - as listas em python são de tipo dinâmico, então não funciona rápido char [] para buffer como eu suponho). Classes semelhantes a Stringbuilder não são otimização prematura por causa do recurso inato de strings em muitas linguagens (imutabilidade) - que permite muitas otimizações (por exemplo, referenciar o mesmo buffer para fatias / substrings). Stringbuilder / stringbuffer / classes semelhantes a stringstream funcionam muito mais rápido do que a concatenação de strings (produzindo muitos pequenos objetos temporários que ainda precisam de alocações e coleta de lixo) e até mesmo ferramentas de formatação de string do tipo printf, sem a necessidade de interpretar a sobrecarga do padrão de formatação que é muito demorada para muitas chamadas de formato.

Mastermind
fonte
-4

Caso você esteja procurando um método rápido de concatenação de strings em Python, não precisa de uma classe StringBuilder especial. A concatenação simples funciona tão bem sem a penalidade de desempenho vista em C #.

resultString = ""

resultString += "Append 1"
resultString += "Append 2"

Veja a resposta de Antoine-tran para resultados de desempenho

Assim como
fonte