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

Resuelto Evan Fosmark asked hace 15 años • 10 respuestas

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

["Hello", "world"].join("-")

Que esto:

"-".join(["Hello", "world"])

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

Evan Fosmark avatar Jan 30 '09 05:01 Evan Fosmark
Aceptado

Esto se debe a que se puede unir cualquier iterable (por ejemplo, lista, tupla, dict, conjunto), pero su contenido y el "unidor" deben ser cadenas.

Por ejemplo:

'_'.join(['welcome', 'to', 'stack', 'overflow'])
'_'.join(('welcome', 'to', 'stack', 'overflow'))
'welcome_to_stack_overflow'

Usar algo que no sean cadenas generará el siguiente error:

TypeError: elemento de secuencia 0: instancia de cadena esperada, int encontrado

recursive avatar Jan 29 '2009 22:01 recursive

Esto se discutió en los métodos String... finalmente en el hilo Python-Dev y fue aceptado por Guido. Este hilo comenzó en junio de 1999 y str.joinse incluyó en Python 1.6, que se lanzó en septiembre de 2000 (y admitía Unicode). Python 2.0 ( strincluidos los métodos compatibles join) se lanzó en octubre de 2000.

  • Se propusieron cuatro opciones en este hilo:
    • separator.join(items)
    • items.join(separator)
    • items.reduce(separator)
    • joincomo función incorporada
  • Guido quería admitir no solo lists y tuples, sino todas las secuencias/iterables.
  • items.reduce(separator)Es difícil para los recién llegados.
  • items.join(separator)introduce una dependencia inesperada de secuencias a str/unicode.
  • join()ya que una función integrada independiente admitiría solo tipos de datos específicos. Por tanto, utilizar un espacio de nombres integrado no es bueno. Si join()tuviéramos que admitir muchos tipos de datos, crear una implementación optimizada sería difícil: si se implementara utilizando el __add__método, sería O(n²).
  • separatorNo se debe omitir la cadena separadora ( ). Lo explícito es mejor que lo implícito.

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

  • El soporte Unicode estaba por llegar, pero no era definitivo. En ese momento, UTF-8 era el que más probablemente estaba a punto de reemplazar a UCS-2/-4. Para calcular la longitud total del búfer para cadenas UTF-8, el método necesita conocer la 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ó la extensión de tipos integrados hasta la versión 2.2. En ese momento era difícil dar iterableclase básica (lo cual se menciona en otro comentario).

La decisión de Guido consta en un correo histórico , decidiendo separator.join(items):

¡Es curioso, pero parece correcto! Barry, adelante...
--Guido van Rossum

Yoshiki Shibukawa avatar Sep 30 '2012 15:09 Yoshiki Shibukawa

Estoy de acuerdo en que al principio es contradictorio, 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, existen dos métodos de unió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 fuera un método de una lista, entonces tendría que inspeccionar sus argumentos para decidir a cuál de ellos llamar. Y no puedes unir byte y str juntos, por lo que la forma en que lo tienen ahora tiene sentido.

Kiv avatar Jan 29 '2009 23:01 Kiv