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


Esto siempre me ha confundido. Parece que esto sería más agradable:

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 cual es así?


1378
2018-01-29 22:45


origen


Respuestas:


Es porque cualquier iterable se puede unir, no solo listas, pero el resultado y el "carpintero" son siempre cadenas.

P.EJ:

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

998
2018-01-29 22:51



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

Estoy de acuerdo, parece gracioso.

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

Nota histórica Cuando aprendí por primera vez   Python, esperaba unirme para ser un método   de una lista, que tomaría el   delimitador como argumento Un montón de   las personas se sienten de la misma manera, y hay   una historia detrás del método de unión. Anterior   a Python 1.6, las cadenas no tenían todo   estos métodos útiles. Hubo un   módulo de cuerda separado que contenía   todas las funciones de cadena; cada   función tomó una cadena como su primera   argumento. Las funciones fueron consideradas   lo suficientemente importante como para poner en el   cuerdas, lo que tiene sentido   para funciones como inferior, superior y   división. Pero muchos Hard-core Python   programadores se opusieron a la nueva unión   método, argumentando que debería ser un   método de la lista en su lugar, o que   no debe moverse en absoluto, sino simplemente quedarse   una parte del antiguo módulo de cuerda (que   todavía tiene muchas cosas útiles en él).   Utilizo el nuevo método de unión exclusivamente,   pero verá el código escrito   manera, y si realmente te molesta,   puede usar la antigua función string.join   en lugar.

--- Mark Pilgrim, Sumérgete en Python


227
2018-01-29 22:48



Esto fue discutido en el Métodos de cadena ... finalmente en el desarrollo de Python-Dev, y fue aceptado por Guido. Este hilo comenzó en junio de 1999, y str.join fue incluido en Python 1.6 que fue lanzado en septiembre de 2000 (y compatible con Unicode). Python 2.0 (compatible str métodos que incluyen join) fue lanzado 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 lists, tuples, pero 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 solo admitiría tipos de datos específicos. Entonces, usar un espacio de nombres incorporado no es bueno. Si join() admite muchos tipos de datos, la creación de una implementación optimizada sería difícil, si se implementa utilizando el __add__ método entonces es O (n²).
  • La cuerda de separación (sep) no debe ser omitido. Explícito es mejor que implícito.

No hay otras razones ofrecidas en este hilo.

Aquí hay algunos pensamientos adicionales (el mío y el de mi amigo):

  • El soporte de Unicode estaba llegando, pero no era definitivo. En ese momento, lo más probable es que UTF-8 reemplazara a UCS2 / 4. Para calcular la longitud total del buffer 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 donde un usuario podía crear una clase similar a una secuencia (iterable). Pero Python no admitió extender los 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 str.join(seq):

Gracioso, pero parece correcto! Barry, adelante ...
  --Guido van Rossum


211
2017-09-30 15:21



Estoy de acuerdo en que es contradictorio al principio, pero hay una buena razón. Unirse no puede ser un método de una lista porque:

  • también debe funcionar para diferentes iterables (tuplas, generadores, etc.)
  • debe tener un comportamiento diferente entre diferentes tipos de cadenas.

En realidad, hay dos métodos de combinación (Python 3.0):

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

Si join era un método de una lista, entonces tendría que inspeccionar sus argumentos para decidir a cuál de ellos llamar. Y no se puede unir byte y str juntos, entonces la forma en que lo tienen ahora tiene sentido.


58
2018-01-29 23:03



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

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

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

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

Vamos a rodar nuestro propio método de unión de listas:

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

Y para usarlo, tenga en cuenta que primero tenemos que crear una lista de cada iterable para unir las cadenas en ese iterable, desperdiciando memoria y potencia 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 de caracteres integrado:

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

Performance Caveat para generadores

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

Por lo tanto, mientras que pasar generadores generalmente es mejor que las listas 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, el str.join operación sigue siendo semánticamente una operación de "cadena", por lo que todavía tiene sentido tenerlo en el str objeto que en iterables misceláneos.


36
2018-04-14 00:45



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

Entiendo por qué es aplicable a algo iterable y, por lo tanto, no se puede implementar fácilmente sólo en la lista.

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


22
2018-01-30 02:43



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. Como el resultado es una cadena, tiene sentido como método de una cadena.


11
2018-01-29 22:51



Ambos no son agradables.

string.join (xs, delimit) significa que el módulo de cadena es consciente de la existencia de una lista, que no tiene ningún conocimiento, ya que el módulo de cadena solo funciona con cadenas.

list.join (delimit) es un poco más agradable porque estamos tan acostumbrados a que las cadenas sean un tipo fundamental (y lingualmente hablando, lo son). Sin embargo, esto significa que la unión debe enviarse dinámicamente porque en el contexto arbitrario de a.split("\n") el compilador de Python podría no saber qué es, y deberá buscarlo (de forma análoga a la búsqueda de Vtable), que es caro si lo haces muchas veces.

Si el compilador de tiempo de ejecución de python sabe que la lista es un módulo integrado, puede omitir la búsqueda dinámica y codificar el intento directamente en el bytecode, mientras que de lo contrario necesita resolver dinámicamente "join" de "a", que puede estar en varias capas de herencia por llamada (ya que entre llamadas, el significado de unión puede haber cambiado, porque python es un lenguaje dinámico).

tristemente, este es el último defecto de la abstracción; no importa qué abstracción elijas, tu abstracción solo tendrá sentido en el contexto del problema que intentas resolver, y como tal nunca podrás tener una abstracción consistente que no se vuelva inconsistente con las ideologías subyacentes a medida que comienzas a pegarlas juntos sin envolverlos en una visión que sea consistente con su ideología. Sabiendo esto, el enfoque de Python es más flexible, ya que es más barato, depende de usted pagar más para que se vea "mejor", ya sea al hacer su propio contenedor o su propio preprocesador.


1
2018-05-07 19:32



- en "-". join (mi_lista) declara que está convirtiendo a una cadena de unir elementos en una lista. Está orientado a resultados (solo para facilitar la memoria y la comprensión)

Hago una hoja de trucos exhaustiva de methods_of_string para su referencia.

string_methonds_44 = {
    'convert': ['join','split', 'rsplit','splitlines', 'partition', 'rpartition'],
    'edit': ['replace', 'lstrip', 'rstrip', 'strip'],
    'search': ['endswith', 'startswith', 'count', 'index', 'find','rindex', 'rfind',],
    'condition': ['isalnum', 'isalpha', 'isdecimal', 'isdigit', 'isnumeric','isidentifier',
                  'islower','istitle', 'isupper','isprintable', 'isspace', ],
    'text': ['lower', 'upper', 'capitalize', 'title', 'swapcase',
             'center', 'ljust', 'rjust', 'zfill', 'expandtabs','casefold'],
    'encode': ['translate', 'maketrans', 'encode'],
    'format': ['format', 'format_map']}

1
2017-12-04 12:22