Curso
Las habilidades de programación en Python no han dejado de crecer en demanda en los últimos años. Para ayudarte a desarrollar tus competencias en Python, hemos recopilado 30 trucos de Python que puedes usar para mejorar tu código. Prueba a aprender uno al día durante los próximos 30 días y echa un vistazo a nuestro artículo sobre buenas prácticas en Python para asegurarte de que tu código está a la altura.
Si tu nivel de Python aún no está donde te gustaría, también puedes ponerte al día con nuestro Python Skill Track.
Trucos de secuencias y estructuras de datos
#1 Slicing
a = "Hello World!"
print(a[::-1])
"""
!dlroW olleH
"""
El slicing es una funcionalidad de Python que, basada en la indexación, permite acceder a un subconjunto de una secuencia. Un índice es simplemente la posición de un elemento dentro de la secuencia. Si el tipo de secuencia es mutable, puedes usar slicing para extraer y modificar datos.
Nota: También podemos aplicar slicing a una secuencia inmutable, pero intentar modificar el slice lanzará un TypeError.
El formato del slicing es: sequence[start:stop:step]. Si no se especifican valores en los parámetros start, stop y step, se aplican los valores por defecto. Estos son:
- "start" por defecto es 0
- "stop" por defecto es la longitud de la secuencia
- "step" por defecto es 1 si no se especifica.
Cuando usamos sequence[start:stop], se devuelven los elementos desde el índice inicial hasta stop - 1 (el índice stop no se incluye).
También podemos pasar índices negativos, que pueden usarse para invertir la secuencia. Por ejemplo, en una lista de 4 elementos, el índice 0 también es el -4, y el último índice también es -1. En el ejemplo anterior, aplicamos esto al parámetro step de la secuencia. Así, la cadena se imprimió al revés, desde el final hasta el índice 0.
#2 Intercambio in situ / asignación simultánea
a = 10
b = 5
print(f"First: {a, b}")
"""
First: (10, 5)
"""
a, b = b, a + 2
print(f"Second: {a, b}")
"""
Second: (5, 12)
"""
Si pensaste que el valor de b sería 7 en lugar de 12, has caído en la trampa del intercambio in situ.
En Python, podemos desempaquetar iterables en variables en una sola asignación gracias al desempaquetado automático. Por ejemplo:
a, b, c = [1, 2, 3]
print(a)
print(b)
print(c)
"""
1
2
3
"""
También podemos recopilar varios valores en una sola variable usando *; este truco de Python se llama empaquetado. Aquí tienes un ejemplo:
a, *b = 1, 2, 3
print(a, b)
"""
1 [2, 3]
"""
Combinar empaquetado y desempaquetado da lugar a la asignación simultánea. Podemos usarla para asignar una serie de valores a una serie de variables de una vez.
#3 Listas vs. tuplas
import sys
a = [1, 2, 3, 4, 5]
b = (1, 2, 3, 4, 5)
print(f"List size: {sys.getsizeof(a)} bytes")
print(f"Tuple size: {sys.getsizeof(b)} bytes")
"""
List size: 52 bytes
Tuple size: 40 bytes
"""
La mayoría de programadores de Python están familiarizados con las listas. No tanto con las tuplas. Ambas son iterables, permiten indexación y almacenar tipos heterogéneos. Pero hay situaciones en las que conviene usar una tupla en lugar de una lista.
Para empezar, las listas son mutables, es decir, podemos modificarlas a voluntad:
a = [1,2,3,4,5]
a[2] = 8
print(a)
"""
[1,2,8,4,5]
"""
Las tuplas, en cambio, son inmutables, por lo que intentar modificarlas lanzará un TypeError.
Por esta razón, las tuplas son más eficientes en memoria, ya que Python puede reservar exactamente el bloque necesario. En una lista, en cambio, se reserva memoria extra por si se amplía: es la asignación dinámica de memoria.
En resumen: si no quieres que los datos cambien, por rendimiento de memoria es preferible usar tuplas frente a listas. Además, las tuplas suelen ser más rápidas.
Aprende más sobre estructuras de datos en Python en este tutorial.
#4 Generadores
a = [x * 2 for x in range(10)]
b = (x * 2 for x in range(10))
print(a)
print(b)
"""
[0, 2, 4, 6, 8, 10, 12, 14, 16, 18]
<generator object <genexpr> at 0x7f61f8808b50>
"""
Las comprensiones de listas son la forma «pythónica» de crear una lista a partir de otro iterable: son mucho más rápidas que un bucle for. Pero ¿qué pasa si cambias accidentalmente [] por ()? Obtienes un generador.
En Python, los paréntesis con la lógica de comprensión crean un generador. Los generadores son un tipo especial de iterable: no almacenan los elementos, sino las instrucciones para generarlos en orden y el estado actual de la iteración.
Cada elemento se genera solo cuando se solicita, mediante evaluación perezosa. La gran ventaja es que consumen mucha menos memoria, ya que no construyen la secuencia completa de una vez.
#5 Aliasing
a = [1, 2, 3, 4 ,5]
b = a
# Change the 4th index in b
b[4] = 7
print(id(a))
print(id(b))
print(a) # Remember we did not explicitly make changes to a.
"""
15136008
15136008
[1, 2, 3, 4, 7]
"""
Python es un lenguaje orientado a objetos: todo es un objeto. Así, asignar un objeto a un identificador crea una referencia a ese objeto.
Cuando asignamos un identificador a otro, acabamos con dos identificadores que referencian el mismo objeto. A esto se le llama aliasing. Los cambios en un alias afectan al otro. A veces es el comportamiento deseado; otras, nos pilla por sorpresa.
Una forma de evitarlo es no crear alias con objetos mutables. Otra opción es clonar el objeto original en lugar de referenciarlo.
La forma más sencilla de clonar es mediante slicing:
b = a[:]
Esto creará una nueva referencia a un objeto lista en el identificador b.
Hay más alternativas, como llamar a list(a) al asignarlo a otro identificador o usar el método copy().
#6 El operador «not»
a = []
print(not a)
"""
True
"""
La forma más sencilla de comprobar si una estructura de datos está vacía es usando el operador not. El not integrado de Python es un operador lógico que devuelve True si la expresión no es verdadera; en caso contrario devuelve False: invierte el valor de verdad de expresiones booleanas y de objetos.
Otra forma habitual de verlo es en una sentencia if:
if not a:
# do something...
Cuando a es True, el operador not devolverá False, y viceversa.
Puede costar un poco al principio; practica para interiorizarlo.
Trucos de cadenas y salida
#7 F-strings
first_name = "John"
age = 19
print(f"Hi, I'm {first_name} and I'm {age} years old!")
"""
Hi, I'm John and I'm 19 years old!
"""
A veces necesitamos formatear cadenas; Python 3.6 introdujo las f-strings para simplificarlo. Para apreciarlas, ayuda conocer cómo se formateaban antes.
Así se hacía tradicionalmente:
first_name = "John"
age = 19
print("Hi, I'm {} and I'm {} years old!".format(first_name, age))
"""
Hi, I'm John and I'm 19 years old!
"""
En esencia, el nuevo método es más rápido, legible y conciso, y reduce errores.
Otro uso de las f-strings es imprimir el nombre del identificador junto con su valor. Esto llegó en Python 3.8.
x = 10
y = 20
print(f"{x = }, {y = }")
"""
x = 10, y = 20
"""
Echa un vistazo a este tutorial sobre formateo con f-strings en Python para saber más.
#8 El parámetro «end» de print()
languages = ["english", "french", "spanish", "german", "twi"]
print(' '.join(languages))
"""
english french spanish german twi
"""
Es muy habitual usar print sin definir sus parámetros opcionales. Por eso, muchos Pythonistas no saben que puedes controlar un poco la salida.
Un parámetro opcional que podemos cambiar es end. Especifica qué se muestra al final de una llamada a print.
El valor por defecto de end es "\n", que indica a Python que empiece una nueva línea. En el ejemplo anterior lo cambiamos por un espacio; así, todos los elementos de la lista se imprimen en la misma línea.
#9 Añadir a una tupla
a = (1, 2, [1, 2, 3])
a[2].append(4)
print(a)
"""
(1, 2, [1, 2, 3, 4])
"""
Ya sabemos que las tuplas son inmutables – ver el truco #3 listas vs. tuplas. Intentar cambiar su estado provoca un TypeError. Pero, si piensas en una tupla como una secuencia de nombres enlazados a objetos que no puedes cambiar, quizá lo veas de otra forma.
Los dos primeros elementos de nuestra tupla son enteros – inmutables. El último es una lista, que en Python sí es mutable.
Si consideramos que la lista es otro nombre de la secuencia enlazado a un objeto, el enlace no cambia, pero el objeto sí puede modificarse desde dentro de la tupla.
¿Lo recomendaríamos en producción? Probablemente no, pero es bueno saberlo.
#10 Unir diccionarios
a = {"a": 1, "b": 2}
b = {"c": 3, "d": 4}
a_and_b = a | b
print(a_and_b)
"""
{"a": 1, "b": 2, "c": 3, "d": 4}
"""
En Python 3.9 y superiores, puedes unir diccionarios con | (OR a nivel de bits). Poco más que añadir: ¡es una solución mucho más legible!
Trucos de estilo y sintaxis
#11 Operador ternario / expresiones condicionales
condition = True
name = "John" if condition else "Doe"
print(name)
"""
John
"""
En el código anterior vemos el llamado operador ternario, también conocido como expresión condicional. Lo usamos para evaluar algo en función de si una condición es True o False.
Otra forma de escribirlo sería:
condition = True
if condition:
name = "John"
else:
name = "Doe"
print(name)
"""
John
"""
Aunque ambas opciones dan el mismo resultado, fíjate en cómo el ternario permite un código más breve y claro. Es la forma más «pythónica» de escribirlo.
#12 Quitar duplicados de una lista
a = [1, 1, 2, 3, 4, 5, 5, 5, 6, 7, 2, 2]
print(list(set(a)))
"""
[1, 2, 3, 4, 5, 6, 7]
"""
La forma más sencilla de eliminar duplicados de una lista es convertirla en un set (y volver a lista si quieres).
En cuanto a mutabilidad, sets y listas son parecidos: podemos añadir y quitar elementos en ambos, pero siguen siendo muy distintos.
Las listas están ordenadas, se indexan desde cero y son mutables. Los sets no están ordenados ni indexados. Sus elementos deben ser de tipo inmutable, aunque el propio set sea mutable; intentar recuperar por índice o modificar un elemento dará error.
Otra diferencia clave: los sets no admiten duplicados. Eso nos permite eliminar los repetidos.
#13 Guion bajo en solitario
>>> print(_)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
>>> 1 + 2
3
>>> print(_)
3
El guion bajo (_) es un identificador válido en Python, así que puedes usarlo para referenciar un objeto. Pero además tiene otra función: almacenar el resultado de la última evaluación.
La documentación dice que «el intérprete interactivo pone el resultado de la última evaluación en la variable _ (se guarda en el módulo builtins, junto a funciones como print)».
Como no habíamos asignado nada a _ antes de llamarlo en la primera línea, obtuvimos un error. Después de calcular 1 + 2, el intérprete guardó el resultado en _.
#14 Guion bajo para ignorar valores
for _ in range(100):
print("The index doesn't matter")
"""
The index doesn't matter
The index doesn't matter
...
"""
En el truco #13 vimos que el intérprete interactivo expone el último resultado en _, pero no es su único caso de uso.
También podemos usarlo para representar objetos que no nos importan o que no vamos a usar más adelante en el programa. Es importante porque usar un identificador «normal» en lugar de _ puede provocar un error F841 al pasar el linter: significa que se asignó una variable local que luego no se usó, lo cual es una mala práctica.
#15 Guion bajo final
list_ = [0, 1, 2, 3, 4]
global_ = "Hi there"
Siguiendo con los usos del guion bajo, otro propósito es evitar conflictos con palabras clave de Python.
PEP 8 menciona que un guion bajo final debe usarse «por convención para evitar conflictos con palabras clave de Python». También indica que «en general es mejor añadir un único guion bajo final que usar abreviaturas o deformar la ortografía. Así, list_ es mejor que lst».
#16 Guion bajo inicial
class Example:
def __init__(self):
self._internal = 2
self.external = 20
A menudo verás a programadores experimentados prefijar un guion bajo a un identificador o método, y con razón.
El guion bajo inicial tiene un significado implícito: esa variable o método es solo para uso interno. Es, básicamente, un aviso a otros programadores definido en PEP 8, pero no forzado por Python. Por tanto, es un indicador débil.
A diferencia de Java, Python no distingue de forma estricta entre variables privadas y públicas. Es decir, tiene sentido porque la comunidad lo ha acordado, pero no afecta al comportamiento del programa.
#17 Guion bajo como separador visual
Último consejo sobre guiones bajos. Hemos visto tres usos, pero puedes consultar nuestro tutorial sobre el papel del guion bajo (_) en Python para profundizar.
number = 1_500_000
print(number)
"""
15000000
"""
Otra forma de usarlo es como separador visual de dígitos en literales enteros, de coma flotante y complejos – se introdujo en Python 3.6.
La idea es mejorar la legibilidad de literales largos o aquellos cuyo valor conviene separar claramente en partes – puedes leer más en PEP 515.
Trucos de estilo y sintaxis
#18 __name__ == "__main__"
if __name__ == "__main__":
print("Read on to understand what is going on when you do this.")
"""
print("Read on to understand what is going on when you do this.")
"""
Es muy probable que hayas visto esta sintaxis en muchos programas: Python usa un nombre especial, "__main__", y lo asigna al identificador __name__ si el archivo que se ejecuta es el programa principal.
Si importamos el módulo mostrado en la captura en otro módulo (archivo Python) y ejecutamos ese archivo, la condición será falsa. Esto es porque, al importar desde otro módulo, el identificador __name__ pasa a ser el nombre del módulo.
#19 El método «setdefault»
import pprint
text = "It's the first of April. It's still cold in the UK. But I'm going to the museum so it should be a wonderful day"
counts = {}
for word in text.split():
counts.setdefault(word, 0)
counts[word] += 1
pprint.pprint(counts)
"""
{'April.': 1,
'But': 1,
"I'm": 1,
"It's": 2,
'UK.': 1,
'a': 1,
'be': 1,
'cold': 1,
'day': 1,
'first': 1,
'going': 1,
'in': 1,
'it': 1,
'museum': 1,
'of': 1,
'should': 1,
'so': 1,
'still': 1,
'the': 3,
'to': 1,
'wonderful': 1}
"""
Puede que quieras establecer un valor para varias claves en un diccionario. Por ejemplo, al contar palabras en un corpus. La manera habitual sería:
- Comprobar si la clave existe en el diccionario
- Si existe, incrementar su valor en 1.
- Si no, añadirla y establecer su valor en 1.
En código quedaría así:
counts = {}
for word in text.split():
if word in counts:
counts[word] += 1
else:
counts[word] = 1
Una forma más concisa es usar el método setdefault() del diccionario.
El primer argumento es la clave a comprobar. El segundo es el valor a establecer si la clave no existe; si existe, el método devuelve su valor y no lo modifica.
Trucos de estructura de programas
#20 Coincidencias con regex
import re
number = re.compile(r"(0)?(\+44)?\d{10}")
num_1 = number.search("My number is +447999999999")
num_2 = number.search("My number is 07999999999")
print(num_1.group())
print(num_2.group())
"""
'+447999999999'
'07999999999'
"""
Las expresiones regulares te permiten definir un patrón de texto a buscar. La mayoría sabe que podemos buscar con CTRL + F (Windows), pero ¿y si no sabes exactamente qué buscar? La respuesta es buscar patrones.
Por ejemplo, los números del Reino Unido siguen un patrón: empiezan por un cero y diez cifras, o por +44 en lugar de cero y diez cifras – el segundo caso es el formato internacional.
Las expresiones regulares ahorran muchísimo tiempo. Si codificáramos reglas para capturar esos casos en lugar de usar regex, podríamos escribir más de 10 líneas.
Aprender cómo funcionan es útil incluso si no programas: la mayoría de editores y procesadores de texto modernos permiten usar regex en buscar y reemplazar.
#21 El «pipe» en regex
import re
heros = re.compile(r"Super(man|woman|human)")
h1 = heros.search("This will find Superman")
h2 = heros.search("This will find Superwoman")
h3 = heros.search("This will find Superhuman")
print(h1.group())
print(h2.group())
print(h3.group())
"""
Superman
Superwoman
Superhuman
"""
Las expresiones regulares tienen un carácter especial, la barra vertical (|), que permite hacer coincidir una de varias expresiones, y puedes usarla en cualquier parte del patrón. Es muy útil cuando tienes varios patrones similares.
Por ejemplo, «Superman», «Superwoman» y «Superhuman» comparten el mismo prefijo. Puedes usar la barra para mantener la parte común y variar lo necesario. Otra vez, ahorro de tiempo.
Ojo: si todas las expresiones que quieres casar aparecen en el mismo texto, se devolverá la primera coincidencia; por ejemplo, «An example text containing Superwoman, Superman, Superhuman» devolvería Superwoman.
#22 El parámetro «sep» de print()
day = "04"
month = "10"
year = "2022"
print(day, month, year)
print(day, month, year, sep = "")
print(day, month, year, sep = ".")
"""
04 10 2022
04/10/2022
04.10.2022
"""
La cantidad de programadores que no conocen todo lo que ofrece print() asusta. Si «Hello World» fue tu primer programa, seguramente print() fue de las primeras funciones que viste. La usamos para mostrar mensajes formateados, pero ofrece mucho más.
En el código anterior mostramos distintas formas de formatear un mensaje. El parámetro sep permite especificar cómo separar los objetos cuando pasamos más de uno a print().
Por defecto los separa con un espacio, pero lo hemos cambiado: una vez con "" y otra con ".".
#23 Funciones lambda
def square(num:int) -> int:
return num ** 2
print(f"Function call: {square(4)}")
"""
Function call: 16
"""
square_lambda = lambda x: x**2
print(f"Lambda function: {square_lambda(4)}")
"""
Lambda functional: 16
"""
Las funciones lambda te llevan a un nivel intermedio-avanzado de lo que puedes hacer con Python – aprende Intermediate Python con este curso. A primera vista parecen complicadas, pero son bastante sencillas.
En el ejemplo usamos un solo argumento, pero podríamos haber usado varios:
square = lambda a, b: a ** b
print(f"Lambda function: {square(4, 2)}")
"""
16
"""
En esencia, la palabra clave lambda permite crear funciones pequeñas, restringidas y anónimas en una línea. Se comportan como una función normal declarada con def, salvo que no tienen nombre.
#24 El método «swapcase»
string = "SoMe RaNDoM sTriNg"
print(string.swapcase())
"""
sOmE rAndOm StRInG
"""
El método swapcase() aplicado a una cadena cambia las mayúsculas por minúsculas y viceversa en una sola línea. No tiene demasiados casos de uso, pero conviene conocerlo.
#25 El método «isalnum»
password = "ABCabc123"
print(password.isalnum())
"""
True
"""
Imagina que creamos un programa que pide una contraseña, pero debe tener combinación de letras y números. Podemos validarlo en una línea llamando a isalnum() sobre la cadena.
El método comprueba si todos los caracteres son alfabéticos (A-Za-z) o numéricos (0-9). Un espacio o símbolo (!#%$&? etc.) devolverá False.
#26 Gestión de excepciones
def get_ration(x:int, y:int) -> int:
try:
ratio = x/y
except ZeroDivisionError:
y = y + 1
ratio = x/y
return ratio
print(get_ration(x=400, y=0))
"""
400.0
"""
Los programas de Python terminan cuando encuentran un error.
A veces no queremos ese comportamiento, por ejemplo cuando hay una persona interactuando con nuestro código. ¿Qué pasaría si el programa se cerrase de golpe?
Hay varias escuelas sobre cómo gestionar casos excepcionales. La mayoría de Pythonistas suele abrazar la idea de que es más fácil pedir perdón que permiso. Es decir, prefieren capturar el error proporcionando el contexto necesario para manejar la excepción, en lugar de intentar prevenir todos los casos posibles.
Pero esto solo funciona si tienes un mecanismo para afrontar el problema cuando ocurre.
#27 Identificar diferencias entre listas
list_1 = [1, 3, 5, 7, 8]
list_2 = [1, 2, 3, 4, 5, 6, 7, 8, 9]
solution_1 = list(set(list_2) - set(list_1))
solution_2 = list(set(list_1) ^ set(list_2))
solution_3 = list(set(list_1).symmetric_difference(set(list_2)))
print(f"Solution 1: {solution_1}")
print(f"Solution 2: {solution_2}")
print(f"Solution 3: {solution_3}")
"""
Solution 1: [9, 2, 4, 6]
Solution 2: [2, 4, 6, 9]
Solution 3: [2, 4, 6, 9]
"""
Tres maneras de comparar diferencias entre dos listas en Python.
Nota: Salvo que sepas con certeza que list_1 es un subconjunto de list_2, la solución 1 no es equivalente a las otras dos.
#28 Args y kwargs
def some_function(*args, **kwargs):
print(f"Args: {args}")
print(f"Kwargs: {kwargs}")
some_function(1, 2, 3, a=4, b=5, c=6)
"""
Args: (1, 2, 3)
Kwargs: {'a': 4, 'b': 5, 'c': 6}
"""
Usamos *args y **kwargs como parámetros cuando no sabemos cuántos argumentos recibirá la función.
*args permite pasar un número variable de argumentos posicionales (sin nombre). Por su parte, **kwargs permite pasar un número arbitrario de argumentos con nombre.
En realidad, *args y **kwargs no tienen nada de mágico: la magia está en los asteriscos (*). Podríamos haber usado cualquier nombre tras los asteriscos, pero args y kwargs son la convención entre desarrolladores de Python.
#29 Elipsis
print(...)
"""
Ellipsis
"""
def some_function():
...
# Alternative solution
def another_function():
pass
Ellipsis es un objeto de Python que puedes invocar escribiendo tres puntos (...) o llamando al propio objeto (Ellipsis).
Su uso más conocido es para acceder y hacer slicing en arrays multidimensionales en NumPy. Por ejemplo:
import numpy as np
arr = np.array([[2,3], [1,2], [9,8]])
print(arr[...,0])
"""
[2 1 9]
"""
print(arr[...])
"""
[[2 3]
[1 2]
[9 8]]
"""
Otro uso de Ellipsis es como marcador de posición en una función aún no implementada.
Es decir, puedes usar Ellipsis, ... o pass, y todos serán válidos.
#30 Comprensiones de listas
even_numbers = [x for x in range(10) if x % 2 == 0 and x != 0]
print(even_numbers)
"""
[2, 4, 6, 8]
"""
El último truco son las comprensiones de listas, una forma elegante de crear una lista a partir de otra secuencia. Permiten aplicar lógica y filtrado sofisticados, como en el ejemplo.
Hay otras formas de lograr lo mismo; por ejemplo, con una lambda:
even_numbers = list(filter(lambda x: x % 2 ==0 and x != 0, range(10)))
print(even_numbers)
"""
[0, 2, 4, 6, 8]
"""
Pero muchos Pythonistas dirían que esta solución es menos legible que la comprensión de listas.
FAQs
¿Cuál es el truco de Python más útil para principiantes?
Probablemente las f-strings sean lo más útil al principio. Hacen el formateo de cadenas más rápido, legible y menos propenso a errores frente a métodos antiguos como .format().
¿Cuál es la forma más rápida de intercambiar dos variables en Python?
Usa asignación simultánea: a, b = b, a. No necesitas una variable temporal: Python evalúa por completo la parte derecha antes de asignar.
¿Cómo uno dos diccionarios en una sola línea?
En Python 3.9+, usa el operador |: merged = dict_a | dict_b. En versiones anteriores, usa {**dict_a, **dict_b}.
¿Cuál es la diferencia entre *args y **kwargs?
*args recopila argumentos posicionales extra en una tupla. **kwargs recopila argumentos con nombre extra en un diccionario. La «magia» está en los operadores * y **, no en los nombres: podrías llamarlos como quieras.
¿Cómo compruebo si una lista está vacía en Python?
Usa el operador not: if not my_list:. Es más «pythónico» que comprobar len(my_list) == 0.
¿Cuál es la diferencia entre una comprensión de lista y un generador?
Una comprensión de lista (corchetes) construye toda la lista en memoria de golpe. Un generador (paréntesis) produce los valores uno a uno bajo demanda, usando mucha menos memoria para secuencias grandes.
¿Cuándo debería usar un operador ternario?
Úsalo para condicionales sencillos en una línea donde ambos resultados sean cortos y claros: name = "John" if condition else "Doe". Para algo más complejo, un bloque if/else tradicional es más legible.
¿Cuál es la forma más fácil de eliminar duplicados de una lista?
Envuelve la lista en set() y vuelve a convertir: list(set(my_list)). Ten en cuenta que los sets no mantienen el orden, así que perderás el orden original.