Aparte de completar la entrada anterior sobre Python, incluyo aquí aquellas cosas que me han vuelto loco en su momento. En especial, las pequeñas GRANDES cosas que no se mencionan en ningún tutorial sobre Python y que he descubierto con sangre.
Conclusiones:
Es el "idiom" más recurrente de Python, y normalmente se explica como "si var tiene algo".
Si se aplica siempre está lógica, morirás en el intento, porque realmente significa:
"si var no es None y no es el valor por defecto para este tipo de variable".
Por tanto estas cosas son True:
Y estas cosas son False:
Ya que el valor por defecto para una cadena de texto es la cadena vacía, para un entero es el cero, para una lista es la lista vacía, etc.
Copia de colecciones
Cuando copiamos una lista o diccionario, estamos copiando en realidad la referencia al objeto, con lo cual si modificamos, el original, se modifica también la copia.
Para evitar esto hay que usar el método 'deepcopy' de la librería externa 'copy':
lista2 = copy.deepcopy(lista1)
En los casos en que nos hay colecciones anidadas, puede bastar una copia superficial (shallow), que puede hacer de estas formas con los diccionarios:
dicc2 = dict(dicc1) dicc2 = dicc1.copy() dicc2 = copy.copy(dicc1)
y de estas formas con las listas:
lista2 = list(lista1) lista2 = copy.copy(lista1)
En realidad sigo sin tener claro como funciona, pero sí puedo advertir de serios efectos colaterales si no se tienen en cuenta ciertas cosas.
En Python se utiliza el paso por valor de referencias a objetos , aunque los valores inmutables (enteros, tuplas...) se comportan como paso por valor. Esto provoca que al pasar un objeto mutable no siempre estemos modificando el objeto original. P.e. Estas dos expresiones son idénticas donde se define el diccionario, pero son completamente distintas si se utilizan sobre una referencia recibida:
dicc = {} # ésta no borra el diccionario "original" dicc.clear() # ésta sí
En cuanto a las variables globales, se puede acceder directamente a ellas, para lectura, desde dentro de una función, siempre que no exista una variable local con su mismo nombre. Pero si intentamos modificar su valor, en realidad creará al vuelo una variable local con su mismo nombre. Para poder modificar una variable global debemos declarla así, dentro de la función:
global mi_variable_global
Nota: si la variable global es mutable (p.e. un diccionario) y no la declaramos con 'global' dentro de una función, no podremos hacer que apunte a otro objeto, pero sí podremos alteraTruer su contenido. Por tanto, nuevamente, dicc={} no borraría el diccionario original, pero dicc.clear(), sí, y dicc['campo1']=3 alteraría el contenido de la variable global.
Ambos tienen sentido solo al pasar parámetros a una función. Hablaré de sucesión o secuencia de parámetros, ya que la palabra "lista" en Python es un tipo de datos. Para mí, la secuencia de parámetros es una cosa rara, que bien se podría asimilar a unos de los tipos o darle una entidad más explícita.
La secuencia de parámetros en la llamada a una función solo puede contener valores sin nombre y valores con nombre separados por comas. Estos últimos tienen que ir al final obligatoriamente, aunque el orden entre ellos no tiene por qué ser el mismo que en la definición de la función.
Al hilo de esto:
Estos operadores sirven para pasar a una función un número variable de parámetros. Cuidado con usar * con un diccionario, ya que el compilador no se quejará, pero por lo general no tiene sentido y su efecto puede ser aleatorio (al no ser los diccionarios ordenados).
En Python 2.7 se introdujeron los SortedDict. Para Python 2.6 se puede usar una implementación completa, añadiendo una librería, o bien, en algunos casos, basta con usar este truco simple para recorrerlo ordenado (siendo d un diccionario):
for k in sorted(d):
print d[k]
También:
Considero Doctest muy útil por ser una forma tremendamente compacta de implementar pruebas unitarias, pero tiene algún comportamiento extraño derivado del hecho de que la parte de comprobación, es una cadena de texto: