python - with - str join sequence




Python join: ¿por qué es string.join(list) en lugar de list.join(string)? (6)

Esto siempre me ha confundido. Parece que esto sería mejor:

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

Que esto:

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

¿Hay alguna razón específica por la que sea así?


¿Por qué es string.join(list) lugar de list.join(string) ?

Esto se debe a que join es un método de "cadena"! Crea una cadena de cualquier iterable. Si pegamos el método en las listas, ¿qué pasa cuando tenemos iterables que no son listas?

¿Qué pasa si tienes una tupla de cuerdas? ¡Si este fuera un método de list , tendría que convertir cada iterador de cadenas como una list antes de poder unir los elementos en una sola cadena! Por ejemplo:

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

Vamos a rodar nuestro propio método de unirse a la lista:

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

Y para usarlo, tenga en cuenta que primero debemos crear una lista de cada iterable para unir las cadenas en ese iterable, desperdiciando tanto la memoria como la capacidad de procesamiento:

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

Así que vemos que tenemos que agregar un paso adicional para usar nuestro método de lista, en lugar de simplemente usar el método de cadena integrado:

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

Advertencia de rendimiento para generadores

El algoritmo que Python usa para crear la cadena final con str.join realidad tiene que pasar la iterable dos veces, por lo que si le proporciona una expresión generadora, primero debe materializarla en una lista antes de que pueda crear la cadena final.

Por lo tanto, si bien la transmisión de generadores suele ser mejor que una lista de comprensión, str.join es una excepción:

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

Sin embargo, la operación str.join sigue siendo semánticamente una operación de "cadena", por lo que todavía tiene sentido tenerla en el objeto str que en varios iterables.


¿Porque el método join() está en la clase de cadena, en lugar de la clase de lista?

Estoy de acuerdo en que se ve divertido.

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

Nota historica Cuando aprendí Python por primera vez, esperaba que unirse fuera un método de una lista, lo que tomaría el delimitador como argumento. Mucha gente siente lo mismo, y hay una historia detrás del método de unión. Antes de Python 1.6, las cadenas no tenían todos estos métodos útiles. Había un módulo de cadena separado que contenía todas las funciones de cadena; Cada función tomó una cadena como su primer argumento. Las funciones se consideraron lo suficientemente importantes como para ponerlas en las propias cuerdas, lo que tenía sentido para funciones como inferior, superior y división. Pero muchos programadores de Python se opusieron al nuevo método de unión, argumentando que debería ser un método de la lista en su lugar, o que no debería moverse en absoluto, sino simplemente permanecer como parte del módulo de cadena antiguo (que todavía tiene muchos de cosas útiles en ella). Utilizo el nuevo método de unión exclusivamente, pero verás el código escrito de cualquier manera, y si realmente te molesta, puedes usar la antigua función string.join.

--- Mark Pilgrim, Sumérgete en Python


Esto se debe a que se puede unir a cualquier iterable, no solo a las listas, sino que el resultado y el "ensamblador" son siempre cadenas.

P.EJ:

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

Esto se discutió en los métodos de Cuerda ... finalmente, el hilo en el programa Python-Dev fue aceptado por Guido. Este hilo comenzó en junio de 1999, y str.join se incluyó en Python 1.6, que se lanzó en septiembre de 2000 (y era compatible con Unicode). Python 2.0 (métodos str compatibles, incluida la join ) se lanzó en octubre de 2000.

  • Hubo cuatro opciones propuestas en este hilo:
    • str.join(seq)
    • seq.join(str)
    • seq.reduce(str)
    • join como una función incorporada
  • Guido quería apoyar no solo la list s, tuple s, sino todas las secuencias / iterables.
  • seq.reduce(str) es difícil para los recién llegados.
  • seq.join(str) introduce una dependencia inesperada de las secuencias a str / unicode.
  • join() como una función incorporada soportaría solo tipos de datos específicos. Así que usar un espacio de nombres incorporado no es bueno. Si join() admite muchos tipos de datos, sería difícil crear una implementación optimizada. Si se implementa con el método __add__ , entonces es O (n²).
  • La cadena separadora ( sep ) no debe omitirse. Explícito es mejor que implícito.

No hay otras razones que se ofrecen en este hilo.

Aquí hay algunos pensamientos adicionales (los míos y los de mi amigo):

  • El soporte de Unicode venía, pero no fue definitivo. En ese momento, era más probable que UTF-8 reemplazara a UCS2 / 4. Para calcular la longitud total del búfer de las cadenas UTF-8 necesita conocer la regla de codificación de caracteres.
  • En ese momento, Python ya había decidido una regla de interfaz de secuencia común en la que un usuario podía crear una clase de secuencia (iterable). Pero Python no admite la extensión de tipos incorporados hasta 2.2. En ese momento era difícil proporcionar una clase iterable básica (que se menciona en otro comentario).

La decisión de Guido se registra en un correo histórico , decidiendo en str.join(seq) :

Divertido, pero parece correcto! Barry, ve por ello ...
--Guido van Rossum


Piense en ello como la operación ortogonal natural para dividir.

Entiendo por qué es aplicable a cualquier cosa iterable y, por lo tanto, no se puede implementar fácilmente solo en la lista.

Para facilitar la lectura, me gustaría verlo en el idioma, pero no creo que sea realmente factible. Si la iterabilidad fuera una interfaz, entonces podría agregarse a la interfaz, pero es solo una convención, por lo que no hay una forma central de hacerlo. Agrégalo al conjunto de cosas que son iterables.


Principalmente porque el resultado de un someString.join() es una cadena.

La secuencia (lista o tupla o lo que sea) no aparece en el resultado, solo una cadena. Debido a que el resultado es una cadena, tiene sentido como método de una cadena.





join