write - tuple join python string




Junção de Python: por que é string.join(list) em vez de list.join(string)? (6)

Por que é string.join(list) vez de list.join(string) ?

Isto é porque join é um método "string"! Cria uma string de qualquer iterável. Se colocarmos o método nas listas, que tal quando temos iteráveis ​​que não são listas?

E se você tiver uma tupla de strings? Se este fosse um método de list , você teria que converter todos os iteradores de strings como uma list antes de poder juntar os elementos em uma única string! Por exemplo:

some_strings = ('foo', 'bar', 'baz')

Vamos rolar nosso próprio método de junção de lista:

class OurList(list): 
    def join(self, s):
        return s.join(self)

E para usá-lo, observe que primeiro temos que criar uma lista de cada iterável para unir as strings naquele iterável, desperdiçando memória e poder de processamento:

>>> l = OurList(some_strings) # step 1, create our list
>>> l.join(', ') # step 2, use our list join method!
'foo, bar, baz'

Então, vemos que temos que adicionar uma etapa extra para usar nosso método de lista, em vez de apenas usar o método de string incorporado:

>>> ' | '.join(some_strings) # a single step!
'foo | bar | baz'

Advertência de desempenho para geradores

O algoritmo que o Python usa para criar a string final com str.join na verdade tem que passar sobre o iterável duas vezes, então, se você fornecer uma expressão geradora, ele terá que materializá-lo em uma lista antes de poder criar a string final.

Assim, enquanto passar em torno de geradores é geralmente melhor que as compreensões de lista, str.join é uma exceção:

>>> import timeit
>>> min(timeit.repeat(lambda: ''.join(str(i) for i in range(10) if i)))
3.839168446022086
>>> min(timeit.repeat(lambda: ''.join([str(i) for i in range(10) if i])))
3.339879313018173

No entanto, a operação str.join ainda é semanticamente uma operação "string", então ainda faz sentido tê-la no objeto str que em iteráveis ​​diversos.

Isso sempre me confundiu. Parece que isso seria melhor:

my_list = ["Hello", "world"]
print my_list.join("-")
# Produce: "Hello-world"

Do que isso:

my_list = ["Hello", "world"]
print "-".join(my_list)
# Produce: "Hello-world"

Existe uma razão específica para isso?


É porque qualquer iterável pode ser unido, não apenas listas, mas o resultado e o "joiner" são sempre strings.

POR EXEMPLO:

import urllib2
print '\n############\n'.join(
    urllib2.urlopen('http://data.stackexchange.com/users/7095'))

Eu concordo que é contraintuitivo no começo, mas há uma boa razão. A associação não pode ser um método de uma lista porque:

  • ele deve funcionar para diferentes iteráveis ​​também (tuplas, geradores, etc.)
  • deve ter um comportamento diferente entre diferentes tipos de strings.

Na verdade, existem dois métodos de junção (Python 3.0):

>>> b"".join
<built-in method join of bytes object at 0x00A46800>
>>> "".join
<built-in method join of str object at 0x00A28D40>

Se join fosse um método de uma lista, então ele teria que inspecionar seus argumentos para decidir qual deles chamar. E você não pode juntar byte e str juntos, então o jeito que eles têm agora faz sentido.


Isso foi discutido nos métodos String ... enfim encadeamentos no Python-Dev achive, e foi aceito por Guido. Esta discussão começou em junho de 1999, e str.join foi incluído no Python 1.6 que foi lançado em setembro de 2000 (e suportado Unicode). O Python 2.0 (métodos str suportados incluindo join ) foi lançado em outubro de 2000.

  • Havia quatro opções propostas neste segmento:
    • str.join(seq)
    • seq.join(str)
    • seq.reduce(str)
    • join como uma função interna
  • Guido queria suportar não apenas list s, tuple s, mas todas as sequencias / iterables.
  • seq.reduce(str) é difícil para os recém-chegados.
  • seq.join(str) introduz dependência inesperada de sequências para str / unicode.
  • join() como uma função interna suportaria apenas tipos de dados específicos. Portanto, usar um namespace interno não é bom. Se join() suporta muitos tipos de dados, criar implementação otimizada seria difícil, se implementado usando o método __add__ , então é O (n²).
  • A string separadora ( sep ) não deve ser omitida. Explícito é melhor que implícito.

Não há outras razões oferecidas neste tópico.

Aqui estão alguns pensamentos adicionais (meus e meus amigos):

  • Suporte Unicode estava chegando, mas não foi final. Naquela época, o UTF-8 era o mais provável para substituir o UCS2 / 4. Para calcular o tamanho total do buffer de strings UTF-8, ele precisa conhecer a regra de codificação de caracteres.
  • Naquela época, o Python já havia decidido sobre uma regra de interface de sequência comum em que um usuário poderia criar uma classe semelhante a uma sequência (iterável). Mas o Python não suportava estender os tipos internos até o 2.2. Naquela época, era difícil fornecer uma classe iterável básica (mencionada em outro comentário).

A decisão de Guido é registrada em um mail histórico , decidindo sobre str.join(seq) :

Engraçado, mas parece certo! Barry, vá em frente ...
- Guido van Rossum


Porque o método join() está na classe string, em vez da classe list?

Eu concordo que parece engraçado.

Veja http://www.faqs.org/docs/diveintopython/odbchelper_join.html :

Nota histórica. Quando aprendi Python pela primeira vez, esperava que join fosse um método de uma lista, que tomaria o delimitador como um argumento. Muitas pessoas sentem o mesmo, e há uma história por trás do método de junção. Antes do Python 1.6, as strings não tinham todos esses métodos úteis. Havia um módulo de string separado que continha todas as funções de string; Cada função tomou uma string como seu primeiro argumento. As funções foram consideradas suficientemente importantes para serem colocadas nas cordas, o que fazia sentido para funções como inferior, superior e dividida. Mas muitos programadores de núcleo duro do Python se opuseram ao novo método de junção, argumentando que ele deveria ser um método da lista, ou que ele não deveria se mover, mas simplesmente permanecer parte do antigo módulo de string (que ainda tem lotes de coisas úteis nele). Eu uso exclusivamente o novo método de junção, mas você verá código escrito de qualquer forma, e se realmente incomoda você, você pode usar a função string.join antiga em vez disso.

--- Mark Pilgrim, Mergulhe em Python


Principalmente porque o resultado de um someString.join() é uma string.

A seqüência (lista ou tupla ou qualquer outra coisa) não aparece no resultado, apenas uma string. Como o resultado é uma string, faz sentido como um método de uma string.







join