Professional Documents
Culture Documents
Aquí hay un muy corto resumen de lo que lo comenzó todo, escrito por Guido van
Rossum:
Tenía muchas quejas sobre el lenguaje ABC, pero tambien me gustaban muchas de sus
características. Era imposible extender el lenguaje ABC (o su implementación) para
solucionar estas quejas -- de hecho su falta de extensibilidad era uno de sus mayores
problemas. Tuve alguna experiencia usando Modula-2+ y hablé con los diseñadores de
Modula-3 y leí el reporte de Modula-3. Modula-3 es el origen de la sintáxis y semántica
usadas para las excepciones, y de otras características de Python.
Se me ocurrió que un lenguaje interpretado con una sintáxis como ABC, pero con
acceso a las llamadas al sistema de Amoeba, cumpliría con la necesidad. Me dí cuenta
de que sería tonto escribir un lenguaje específico a Amoeba, por lo que decidí que
necesitaba un lenguaje que sea generalmente extensible.
Durante las vacaciones de la Navidad de 1989, tuve mucho tiempo libre, y decidí
intentarlo. Durante el año siguiente, mientras todavía trabajaba en él principalmente en
mi propio tiempo, Python era usado en el proyecto Amoeba con éxito creciente, y la
realimentación de mis colegas le agregó muchas de sus tempranas mejoras.
El lenguaje viene con una gran biblioteca estándar que cubre áreas tales como
procesamiento de texto (expresiones regulares, Unicode, calcular diferencias entre
archivos), protocolos de Internet (HTTP, FTP, SMTP, XML-RPC, POP, IMAP,
programación CGI), ingeniería de software (prueba de unidades, hacer bitácoras,
estudios de rendimiento, análisis gramatical de código Python), e interfaces de sistemas
operativos (llamadas al sistema, sistemas de archivos, sockets TCP/IP). Mire la tabla de
contenidos de la Referencia de la Biblioteca para tener una idea de lo que hay
disponible. Una gran variedad de extensiones de terceros también están disponibles.
Consulte el Indice de Paquetes Python para encontrar paquetes que sean de su interés.
Las versiones de Python son numeradas A.B.C o A.B. A es el número mayor de versión
-- sólo se incrementa para cambios realmente grandes en el lenguaje. B es el número
menor de version, incrementado por cambios menos trascendentales. C es el micronivel
-- se incrementa por cada lanzamiento de corrección de errores. Mire la PEP 6 para más
información sobre lanzamientos de corrección de errores.
Las versiones alfa, beta, y lanzamientos propuestos tienen un sufijo adicional. El sufijo
para una versión alfa es "aN" para algún número pequeño N, el sufijo para una versión
beta es "bN" para algún número pequeño N, y el sufijo para un lanzamiento propuesto
es "cN" para algún número pequeño N. En otras palabras, todas las versiones
etiquetadas 2.0aN preceden a las versiones etiquetadas 2.0bN, las cuales preceden a las
versiones 2.0cN, y todas ellas preceden a la 2.0.
Puede tambien encontrar números de versiones con un sufijo "+", ej. "2.2+". Estas son
versiones sin lanzamiento, construidas directamente del tronco Subversion. En la
práctica, luego de que se hizo un lanzamiento menor final, se incrementa el tronco
Subversion a la próxima version menor, la cual se convierte en la versión "a0", ej.
"2.4a0".
Vea también la documentación para sys.version, sys.hexversion, y
sys.version_info.
No realmente. Puede hacer lo que quiera con los códigos fuentes, mientras deje dentro
los derechos de autor, y muestre esos derechos en cualquier documentación sobre
Python que produzca. Tampoco use el nombre del Instituto ni del autor en publicidades
sin antes obtener un permiso escrito, y no lo haga responsable por nada (lea los
derechos de autor actuales para una mayor precisión legal).
Si honra las reglas de derechos de autor, está bien usar Python para un fin comercial,
vender copias de Python en forma binaria o sus fuentes (modificadas o no), o vender
productos que mejoren Python o incorporen Python (o parte de él) en alguna forma. Por
supuesto, nos gustaría conocer acerca de todo uso comercial de Python.
Hay disponibles numerosos tutoriales y libros. Consulte la Guía del Principiante para
encontrar información para los programadores principiantes de Python, incluyendo
listas de tutoriales.
Puede encontrarse más información acerca de otras listas de correo y grupos de noticias
en http://www.python.org/community/lists.html.
Todos los lanzamientos, incluyendo las alfas, betas y lanzamientos propuestos, son
anunciados en los grupos comp.lang.python y comp.lang.python.announce. Todos los
anuncios también aparecen en la página home de Python, en http://www.python.org; un
suministro RSS de noticias también está disponible.
Para reportar un error o enviar un parche, por favor use el servicio Roundup en
http://bugs.python.org/.
Debe tener un usuario en Roundup para reportar errores; esto nos permite contactarlo si
tenemos algunas preguntas. Tambien le permite a Roundup enviarle actualizaciones
cuando trabajamos en su error. (XXX translate:) If you previously had used
SourceForge to report bugs to Python, you can obtain your Roundup password through
Roundup's password reset procedure.
1.12 ¿Hay publicado algún artículo sobre Python al que pueda hacer
referencia?
Guido van Rossum y Jelke de Boer, "Interactively Testing Remote Servers Using the
Python Programming Language", CWI Quarterly, Volumen 4, Edición 4 (Diciembre
1991), Amsterdam, pp 283-303.
Puede también buscar en librerías en linea por "Python" y filtrar las referencias a Monty
Python; o quizás buscar por "Python" y "lenguaje".
Al mismo tiempo que comenzó a implementar Python, Guido van Rossum estaba
también leyendo los guiones publicados de "Monty Python's Flying Circus" (una serie
de comedia de los setenta, en el extraño caso que no lo conozca). Se le ocurrió que
necesitaba un nombre que sea corto, único, y ligeramente misterioso, por lo que decidió
llamar Python al lenguaje.
PEP 1 explica el proceso de las PEP y su formato; léalo primero si quiere proponer una
PEP.
En general, no. Existen ya millones de lineas de código Python alrededor del mundo, de
manera de que cualquier cambio en el lenguaje que invalide más que una muy pequeña
fracción de programas existentes tiene que ser desaprobada. Incluso si puede proveer un
programa de conversión, todavía está el problema de actualizar toda la documentación;
muchos libros fueron escritos sobre Python, y no queremos invalidarlos a todos de un
solo golpe.
Las donaciones a PSF son exentas de impuestos en Estados Unidos. Si usa Python y lo
encuentra útil, por favor contribuya vía la página de donación a PSF.
Python hace muy pocos cálculos de fecha, y para esas que hace se basa en las funciones
de la biblioteca de C. Python generalmente representa el tiempo como segundos desde
1970 o como una tupla (año, mes, día, ...) donde el año es expresado con cuatro
dígitos, lo que hace que un error Y2K sea improbable. Entonces, mientras su biblioteca
de C esté bien, Python debería estar bien. Por supuesto, es posible que una aplicación en
particular escrita en Python haga suposiciones acerca de años de 2 dígitos.
Ya que Python está disponible sin cargo, no hay garantías absolutas. Si hay problemas
desapercibidos, la responsabilidad es del usuario y no de los desarrolladores, y no hay
nadie al que pueda hacer juicio por los daños. Los derechos de autor de Python contiene
la siguiente retractación:
4. PSF hace disponible a Python 2.3 al Licenciado en una base "como está". PSF
NO DA REPRESENTACIONES O GARANTIAS, EXPRESAS O
IMPLICITAS. A MODO DE EJEMPLO, PERO NO LIMITANDO, PSF NO
HACE NI RENUNCIA NINGUNA REPRESENTACION O GARANTIA DE
CAPACIDAD DE COMERCIO O APTITUD PARA NINGUN PROPOSITO
EN PARTICULAR O QUE EL USO DE PYTHON 2.3 NO INFLIGIRA
NINGUN DERECHO DE TERCEROS.
5. PSF NO SE RESPONSABILIZARA ANTE EL LICENCIADO O NINGUN
OTRO USUARIO DE PYTHON 2.3 POR DAÑO O PERDIDA INCIDENTAL,
ESPECIAL O CONSIGUIENTE COMO RESULTADO DE MODIFICAR,
DISTRIBUIR O CUALQUIER OTRO USO DE PYTHON 2.3, O
CUALQUIER DERIVADO DEL MISMO, INCLUSO SI SE AVISA DE LA
POSIBILIDAD DEL MISMO.
Las buenas noticias es que si encuentra un problema, tiene las fuentes completas
disponible para rastrearlo y solucionarlo. Esta es una ventaja del entorno de desarrollo
de código fuente abierto.
Si. Si quiere hablar sobre el uso de Python en educación, quizás esté interesado en
unirse a la lista de correo edu-sig.
Es todavía normal que los estudiantes comiencen con (una parte de) un lenguaje
procedural tipado estáticamente como Pascal, C, o una parte de C++ o Java. Los
estudiantes quizás tengan mejor provecho aprendiendo Python como su primer lenguaje.
Python tiene una sintáxis muy simple y consistente, y una gran biblioteca estándar. Y lo
más importante, usar Python en un curso de introducción a la programación permite a
los estudiantes concentrarse en habilidades importantes para la programación, tales
como descomposición del problema y diseño de tipos de datos. Con Python, los
estudiantes pueden ser rapidamente introducidos en conceptos básicos como
procedimientos y lazos. Incluso pueden probablemente trabajar con objetos definidos
por el usuario en su primer curso.
Para un estudiante que nunca programó antes, usar un lenguaje tipado estáticamente le
parece antinatural. Le presenta una complejidad adicional que el estudiante debe
dominar y disminuye la velocidad del curso. Los estudiantes intentan aprender a pensar
como una computadora, descomponer problemas, diseñar interfaces consistentes, y
encapsular datos. Mientras aprender a usar un lenguaje tipado estáticamente es
importante a largo plazo, no es necesariamente el mejor tema para ver en el primer
curso de programación.
Muchos otros aspectos de Python lo hacen un buen primer lenguaje. Como Java, Python
tiene una gran biblioteca estándar, de manera que en el curso pronto se puede asignar a
los estudiantes proyectos de programación que hagan algo. Las tareas no se restringen a
la calculadora estándar de cuatro funciones y programas de balances de cuentas. Usando
la biblioteca estándar, los estudiantes pueden obtener la satisfacción de trabajar en
aplicaciones realísticas mientras aprenden los fundamentos de la programación. Usar la
biblioteca estándar tambien enseña a los estudiantes a reusar código. Los módulos de
terceros como PyGame son también útiles para extender el alcance de los estudiantes.
>>> L = []
>>> dir(L)
['append', 'count', 'extend', 'index', 'insert', 'pop', 'remove',
'reverse', 'sort']
>>> help(L.append)
Help on built-in function append:
append(...)
L.append(object) -- append object to end
>>> L.append(1)
>>> L
[1]
Con el intérprete, la documentación nunca está lejos del estudiante mientras programa.
También hay buenos IDEs para Python (N.T.: IDE es Entorno de Desarrollo Integrado).
IDLE es un IDE multiplataforma para Python que está escrito en Python usando
Tkinter. PythonWin es un IDE específico para Windows. Los usuarios de Emacs se
alegrarán al saber que hay un muy buen modo Python para Emacs. Todos estos entornos
de programación ofrecen resaltado de sintáxis, auto-sangría, y acceso al intérprete
interactivo mientras se programa. Consulte http://www.python.org/editors/ para una
lista completa de los entornos de edición para Python.
3 Actualizando Python
3.1 ¿Qué es este módulo bsddb185 del que se queja mi aplicación?
Usando su versión vieja de Python y un par de programas que son parte de Python 2.3
(db2pickle.py y pickle2db.py, en el directorio Tools/scripts) usted puede convertir sus
viejos archivos de base de datos al formato nuevo. Usando su versión vieja de Python,
ejecute el programa db2pickle.py para convertir a pickle, por ejemplo:
mv database.db olddatabase.db
Las órdenes exactas que use variarán dependiendo de los detalles de su instalación. Para
detalles completos sobre la operación de estos dos programas, vea el texto de
documentación al comienzo de cada uno.
4 Diseño de Python
4.1 ¿Por qué Python usa sangrías para agrupar expresiones?
Guido van Rossum cree que usar sangrías para agrupar es extremadamente elegante y
contribuye mucho a la claridad del programa Python promedio. La mayoría de las
personas aprenden a amar esta característica luego de un tiempo.
if (x <= y)
x++;
y--;
z++;
4.2 ¿Por qué los cálculos de punto flotante son tan inexactos?
>>> 1.2-1.0
0.199999999999999996
En base 2, 1/2 = 0.1, 1/4 = 0.01, 1/8 = 0.001, etc. .2 es igual a 2/10 que es igual a 1/5,
resultando en el número binario fraccional 0.001100110011001...
Los números de punto flotante tienen solamente 32 o 64 bits de precision, por lo que se
cortan los dígitos en algún punto, y el número resultante es 0.199999999999999996 en
decimal, no 0.2.
La función repr() de un punto flotante muestra tantos dígitos como sea necesario para
hacer verdad a eval(repr(f)) == f para cualquier flotante f. La función str()
muestra menos dígitos, y esto frecuentemente resulta en un número más sensible que el
que probablemente se pretendía:
>>> 0.2
0.20000000000000001
>>> print 0.2
0.2
Nuevamente, esto no tiene nada que ver con Python, sino con la manera en que la
plataforma subyacente de C maneja los números de punto flotante, y de última con la
imprecisión que siempre tendrá al escribir números como una cadena de una cantidad
fija de dígitos.
Por favor consulte el capítulo sobre aritmética de punto flotante en el tutorial de Python
para más información.
La otra es que las cadenas en Python se consideran tan "elementales" como los
números. Ninguna actividad cambiará el valor 8 a nada más, y en Python, ninguna
actividad cambiará la cadena "ocho" a nada más.
La idea fue prestada de Modula-3. Resultó ser muy útil, por una variedad de razones.
Primero, es más obvio que está usando un método o un atributo de la instancia en lugar
de una variable local. Leer self.x o self.meth() hace absolutamente claro que se usa
una variable de instancia o un método incluso si no sabe de memoria la definición de la
clase. En C++, medio puede decirse por la ausencia de una declaración de variable local
(asumiendo que las globales sean escasas o facilmente reconocibles) -- pero en Python,
no hay declaraciones de variables locales, de manera que tendría que examinar la
definición de la clase para estar seguro. Algunos estándares de programación de C++ y
Java piden que los atributos de instancia tengan el prefijo m_, por lo que hacerlo
explícito es también útil en esos lenguajes.
Mucha gente acostumbrada a C o Perl se queja de que ellos quieren usar este modismo:
while True:
linea = f.readline()
if not linea:
break
...hacer algo con linea...
if (x = 0) {
...manejo de errores...
}
else {
...código que sólo trabaja para x no cero...
}
Hay una manera alternativa de deletrear esto que parece atractiva pero es generalmente
menos robusta que la solución "while True":
linea = f.readline()
while linea:
...hacer algo con linea...
linea = f.readline()
El problema con esto es que si cambia de opinión acerca de cómo exactamente obtener
la siguiente linea (ej. quiere cambiarlo a sys.stdin.readline()) tiene que recordar de
cambiar dos lugares en su programa -- la segunda ocurrencia está oculta al final del
lazo.
for linea in f:
...hacer algo con linea...
4.6 ¿Por qué Python usa métodos para alguna funcionalidad (ej.
list.index()) pero funciones para otra (ej. len(list))?
La principal razón es historia. Las funciones se utilizaron para las operaciones que eran
genéricas para un grupo de tipos y que se pretendían funcionaran incluso con objetos
que no tenían ningún método (ej. tuplas). Es también conveniente tener una función que
pueda ser rapidamente aplicada a una colección amorfa de objetos cuando usa las
características funcionales de Python (map(), apply() et al).
Note que para las operaciones sobre cadenas de caracteres, Python cambió de funciones
externas (el módulo string) a métodos. Sin embargo, len() es todavía una función.
Las cadenas se vuelven mucho más parecidas a otros tipos estándares a partir de Python
1.6, cuando se agregaron métodos que dan la misma funcionalidad que siempre estuvo
disponible usando las funciones del módulo string. La mayoría de estos nuevos métodos
fueron ampliamente aceptados, pero el único que parece incomodar a algunos
programadores es:
"1, 2, 4, 8, 16"
El primero corre por el sendero de: "Parece realmente feo usar un método de un literal
de cadena (constante de cadena)", al cual la respuesta es que quizás, pero un literal de
cadena es solamente un valor fijo. Si los métodos van a permitirse en nombres
vinculados a cadenas no hay una razón lógica de no hacerlos disponibles a los literales.
Ya que es un método de cadena, puede trabajar para cadenas Unicode tanto como para
cadenas ASCII plano. Si join() fuese un método de los tipos de secuencia, entonces los
tipos de secuencia tendrían que decidir que tipo de cadena devolver dependiendo del
tipo del separador.
try:
valor = dicc[clave]
except KeyError:
dicc[clave] = getvalor(clave)
valor = dicc[clave]
Esto sólo tenía sentido cuando esperaba que el diccionario tenga la clave casi todo el
tiempo. Si no era el caso, se codificaba así:
if dicc.has_key(clave):
valor = dicc[clave]
else:
dicc[clave] = getvalor(clave)
valor = dicc[clave]
(En Python 2.0 y superiores, puede codificar esto como valor =
dicc.setdefault(clave, getvalor(clave)).)
Usted puede hacer esto lo suficientemente fácil con una secuencia de if... elif...
elif... else. Han habido algunas propuestas de una sintáxis para la expresión switch,
pero no hay (aún) consenso en como hacer las pruebas de rangos. Vea la PEP 275 para
los detalles completos y el estado actual.
Para los casos donde necesite elegir entre un número muy grande de posibilidades,
puede crear un diccionario mapeando valores de casos a llamadas de función. Por
ejemplo:
func = funciones[valor]
func()
Para llamar a métodos de objetos, puede simplificarlo más aún usando la función
integrada getattr() para recuperar métodos con un nombre en particular:
Se sugiere que use un prefijo para los nombres de método, como el visitar_ en este
ejemplo. Sin dicho prefijo, si los valores vienen de una fuente no confiable, un atacante
sería capaz de llamar cualquier método de su objeto.
Respuesta 2: Afortunadamente, hay un Python Sin Pilas: Stackless Python, el cual tiene
un lazo de intérprete completamente rediseñado que evita la pila de C. Es todavía
experimental pero luce muy prometedor. A pesar de que es compatible a nivel binario
con el Python standard, no es todavía claro si el Stackless se abrirá paso al núcleo --
quizás sea demasiado revolucionario.
4.11 ¿Por qué las formas lambda no pueden contener expresiones?
Las funciones son objetos de primera clase en Python, y pueden declararse en el ámbito
local. Por lo tanto, la única ventaja de usar una forma lambda en lugar de una función
definida localmente es que no se necesita inventar un nombre para la función -- pero es
solamente una variable local a la cual se asigna el objeto función (¡que es exactamente
el mismo tipo de objeto que genera una forma lambda!).
No hay una diferencia de performance una vez que se cargó el archivo .pyc, ya que el
código de byte leído del archivo .pyc es exactamente el mismo que el creado en la
traducción directa. La única diferencia es que cargar el código de un archivo ".pyc" es
más rápido que analizar y traducir un archivo .py, por lo que la presencia de archivos
.pyc precompilados mejora el tiempo de arranque de las rutinas de Python. Si se desea,
el módulo lib/compileall.py puede usarse para crear archivos .pyc válidos para un
conjunto dado de módulos.
Note que el programa principal ejecutado por Python, aún si el nombre del archivo
termina en .py, no es compilado a un archivo .pyc. Se compila a código de byte, pero
este código no se graba en un archivo. Normalmente los programas principales son
bastante cortos, por lo que esto no es costoso a nivel de velocidad.
También hay varios programas que facilitan cruzar código Python y C de varias
maneras para mejorar la performance. Vea, por ejemplo, Psyco, Pyrex, PyInline,
Py2Cmod, y Weave.
A veces los objetos se traban temporalmente en las trazas de retorno y por lo tanto no
son removidos cuando usted lo esperaría. Limpie las trazas de retorno con:
import sys
sys.exc_clear()
sys.exc_traceback = sys.last_traceback = None
Las trazas de retorno son usadas para reportar errores, implementar depuradores y cosas
relacionadas. Contienen una porción del estado del programa extraída durante el manejo
de una excepción (normalmente la excepción más reciente).
¿Por qué no usa Python un esquema de recolección de basura más tradicional? Por un
lado, esto no es una característica estándar de C y por lo tanto no es portable. (Sí,
conocemos la biblioteca Boehm GC. Tiene porciones de código de máquina para las
plataformas más comunes, no para todas, y a pesar de que es mayormente transparente,
no lo es completamente; se necesitan parches para lograr que Python trabaje con ella.)
Los objetos referenciados desde el espacio global de nombres de los módulos de Python
no se remueven siempre que termina Python. Esto puede suceder si hay referencias
circulares. También hay algunos bits de memoria que son tomados por la biblioteca de
C que son imposibles de liberar (ej. una herramienta como Purify se quejará de esto).
Python es, sin embargo, agresivo acerca de limpiar la memoria al terminar y trata de
destruir todos los objetos.
Si quiere forzar a Python para que borre ciertas cosas al salir, use el gancho
sys.exitfunc() para ejecutar una función que forzará esas eliminaciones.
Las listas y las tuplas, similares en muchos aspectos, son generalmente usadas en modos
fundamentalmente diferentes. Las tuplas pueden pensarse como similares a los registros
de Pascal o las estructuras de C; son pequeñas colecciones de datos relacionados los
cuales pueden ser de tipos diferentes y son operados como un grupo. Por ejemplo, una
coordenada cartesiana se representa apropiadamente como una tupla de dos o tres
números.
Las listas, por otro lado, son más como los arreglos en otros lenguajes. Tienden a tener
un número variable de objetos los cuales son del mismo tipo y son operados uno por
uno. Por ejemplo, os.listdir('.') devuelve una lista de cadenas representando los
archivos en el directorio actual. Las funciones que operan sobre esta salida
generalmente no fallarán si usted agregó un archivo o dos al directorio.
Las tuplas son inmutables, lo que significa que una vez que se creó una tupla, no se
puede reemplazar ninguno de sus elementos con otro valor. Las listas son mutables, lo
que significa que usted siempre puede cambiar los elementos de una lista. Solamente los
elementos inmutables son usados como claves de los diccionarios, por lo que solamente
pueden usarse como claves las tuplas y no las listas.
Las listas de Python son realmente arreglos de longitud variable, no listas enlazadas al
estilo de Lisp. La implementación usa un arreglo contiguo de referencias a otros
objetos, y mantiene un puntero a este arreglo y la longitud del arreglo en el encabezado
de la lista.
Esto hace que indizar una lista (a[i]) sea una operación cuyo costo es independiente
del tamaño de la lista o el valor del índice.
Los diccionarios trabajan calculando un código hash para cada clave almacenada en el
diccionario usando la función integrada hash(). El código hash varía ampliamente
dependiendo de la clave; por ejemplo, el hash de "Python" es -539294296 mientras que
"python", una cadena que difiere en un sólo bit, tiene como hash a 1142331976. El
código hash es por lo tanto utilizado para calcular una ubicación en el arreglo interno
donde se almacenará el valor. Asumiendo que está almacenando claves que tienen todas
valores diferentes de hash, esto significa que los diccionarios tardan una suma constante
de tiempo -- O(1) en notación de ciencias de computadora -- en buscar una clave.
También significa que no se mantiene el órden de las claves, y atravesar el arreglo como
lo hacen .keys() y .items() entregará el contenido del diccionario en algún órden
arbitrario.
4.18 ¿Por qué las claves de los diccionarios deben ser inmutables?
La implementación de las tablas hash de los diccionarios usan un valor hash calculado a
partir del valor de la clave para encontrar la entrada del diccionario. Si la clave fuese un
objeto mutable, su valor podría cambiar, y por lo tanto su hash también podría cambiar.
Pero ya que quien cambie el objeto clave no puede decirle que está siendo usado como
clave de un diccionario, no puede mover la entrada en el diccionario. Por lo tanto,
cuando trate de buscar el mismo objeto en el diccionario, no será encontrado porque su
valor hash es diferente. Si intenta buscar el valor viejo tampoco se encontrará, porque el
valor del objeto encontrado en la caja del hash sería distinto.
Si quiere indizar un diccionario con una lista, simplemente convierta primero la lista a
una tupla; la función tuple(L) crea una tupla con las mismas entradas que la lista L.
Las tuplas son inmutables y por lo tanto pueden ser usadas como claves para
diccionarios.
• Hacer el hash de las listas con las direcciones (IDs de los objetos). Esto no
funciona porque si construye una nueva lista con el mismo valor, no será
encontrada; ej.:
• d = {[1,2]: '12'}
• print d[[1,2]]
generará una excepción KeyError porque el id de la [1,2] usada en la segunda
linea difiere de aquella de la primera linea. En otras palabras, las claves de
diccionarios deben ser comparadas usando ==, no usando is.
• Hacer una copia cuando se usa la lista como clave. Esto no funciona porque la
lista, al ser un objeto mutable, puede contener una referencia a si misma, por lo
que el código de copiado caería en un lazo infinito.
• Permitir listas como claves pero decirle al usuario que no las modifique. Esto
permitiría un tipo de errores difíciles de tracear en programas donde se olvidó o
modificó una lista por accidente. También invalida una importante regla de los
diccionarios: cada valor en d.keys() es usable como clave del diccionario.
• Marcar las listas como de sólo lectura una vez que fueron usadas como clave de
un diccionario. El problema es que no es solamente el objeto del nivel superior
el que puede cambiar su valor; usted podría usar una tupla conteniendo una lista
como clave. Entrando cualquier cosa como clave en un diccionario requeriría
marcar todos los objetos alcanzables desde allí como de sólo lectura -- y
nuevamente, objetos autoreferenciados podrían causar un lazo infinito.
Hay un truco para evitar esto si es necesario, pero úselo bajo su propio riesgo: Puede
envolver una estructura mutable con una instancia de una clase que tenga ambos
métodos __cmp__ y __hash__. Debe asegurarse que el valor del hash para todos los
objetos envolventes que residan en un diccionario (u otra estructura basada en hash),
permanezcan fijos mientras el objeto esté en el diccionario (u otra estructura):
class EnvuelveLista:
def __init__(self, la_lista):
self.la_lista = la_lista
def __cmp__(self, otro):
return self.la_lista == otro.la_lista
def __hash__(self):
l = self.la_lista
resultado = 98767 - len(l)*555
for i in range(len(l)):
try:
resultado = resultado + (hash(l[i]) % 9999999) *
1001 + i
except:
resultado = (resultado % 7777777) + i * 333
return resultado
Note que el cálculo del hash es complicado por la posibilidad de que algunos miembros
de la lista puedan no ser hasheables y también por la posibilidad de una sobrecarga
aritmética.
En situaciones donde la performance importa, hacer una copia de la lista solamente para
ordenarla sería ineficiente. Por lo tanto, list.sort() ordena la lista en su lugar. Para
recordarle ese hecho, no devuelve la lista ordenada. De esta manera, no será engañado
al accidentalmente sobreescribir una lista cuando necesita una copia ordenada pero
tambien necesita mantener la copia sin ordenar.
Como resultado, aquí hay un modismo para iterar sobre las claves ordenadas de un
diccionario:
claves = dicc.keys()
claves.sort()
for clave in claves:
...hacer lo que sea con dicc[clave]...
Una especificación de interfaz para un módulo, tal como es provisto por lenguajes como
C++ y Java, describe los prototipos para los métodos y funciones del módulo. Muchos
sienten que un refuerzo en tiempo de compilación de la especificación de interfaz ayuda
en la construcción de programas grandes. Python no soporta directamente
especificaciones de interfaz, pero muchas de sus ventajas pueden obtenerse por una
apropiada disciplina de pruebas por componentes, la cual frecuentemente puede lograrse
muy facilmente en Python. Hay también una herramienta, PyChecker, que puede usarse
para encontrar problemas originados al subclasear.
Este tipo de error normalmente es cometido por programadores neófitos. Considere esta
función:
La primera vez que llama a esta función, D contiene un sólo item. La segunda vez, D
contiene dos items porque cuando foo() comienza a ejecutarse, D arranca con un item
en él.
Frecuentemente se espera que una llamada a una función cree objetos nuevos para los
valores por defecto. Esto no es lo que sucede. Valores por defecto son creados
exactamente una vez, cuando se define la función. Si se cambia ese objeto, como al
diccionario en este ejemplo, las subsecuentes llamadas a la función harán referencia al
objeto cambiado.
Por definición, los objetos inmutables como números, cadenas de texto, tuplas, y None,
están a salvo del cambio. Cambios a objetos mutables como diccionarios, listas, e
instancias de clases pueden llevar a confusión.
def foo(dict={}):
...
sino:
def foo(dict=None):
if dict is None:
dict = {} # crea un nuevo diccionario en el espacio local
de nombres
Esta característica puede ser útil. Cuando tiene una función que consume mucho tiempo
de cálculo, una técnica común es hacer un caché de los parametros y del valor resultante
de cada llamada a la función, y devolver el valor en el caché si el mismo valor es pedido
nuevamente. Esto es llamado "memorización", y puede implementarse así:
# Calcular el valor.
resultado = ... cálculo muy caro ...
_cache[(arg1, arg2)] = resultado # Guardamos el resultado en el
caché
return resultado
Puede usar una variable global conteniendo el diccionario en lugar del valor por
defecto; es cuestión de gusto.
Puede usar excepciones para proveer un "goto estructurado" que incluso funciona a
través de llamadas a funciones. Muchos sienten que las excepciones pueden emular
convenientemente todos los usos razonables de las construcciones "go" o "goto" de C,
Fortran, y otros lenguajes. Por ejemplo:
try:
...
if (condición): raise etiqueta() # goto etiqueta
...
except etiqueta: # a dónde ir con el goto
pass
...
Esto no le permite saltar al medio de un lazo, pero de cualquier manera eso se considera
como un abuso del goto. Usese con moderación.
4.24 ¿Por qué las cadenas de texto crudas (raw strings) no pueden
terminar con una barra invertida?
Más precisamente, no pueden terminar con un número impar de barras invertidas: las
barras invertidas sin par al final afectan al caracter de cierre de la cadena, dejando una
cadena de texto sin terminar.
Las cadenas crudas fueron diseñadas para facilitar la creación de entradas para
procesadores (principalmente motores de expresiones regulares) que quieren hacer su
propio procesamiento de escape de barras invertidas. De cualquier manera, tales
procesadores consideran un error una barra invertida sin par al final. Por otra parte, le
permiten evadir un caracter de cierre de la cadena escapándolo con una barra invertida.
Estas reglas trabajan bien cuando las cadenas crudas se usan para el propósito
pretendido.
Si está intentando construir caminos de directorios para Windows, note que todas las
llamadas al sistema de Windows aceptan también barras normales:
Si está intentando construir un camino de directorio para una órden de DOS, pruebe
como en uno de los siguientes ejemplos:
4.25 ¿Por qué Python no tiene una expresión "with" como otros
lenguajes?
Algunos lenguajes, como Object Pascal, Delphi, y C++ usan un tipado estático.
Entonces es posible saber, sin ambigüedades, que miembro se asigna en una cláusula
"with". Este es el punto principal - el compilador siempre conoce el ámbito de cada
variable en tiempo de compilación.
Python usa un tipado dinámico. Es imposible saber por adelantado cual atributo será
referenciado en tiempo de ejecución. Los atributos miembros pueden agregarse o
eliminarse de los objetos en cualquier momento. Esto haría imposible saber, con una
simple lectura, cual atributo está siendo referenciado - uno local, global, o atributo
miembro.
def foo(a):
with a:
print x
El ejemplo asume que "a" debe tener un atributo miembro llamado "x". Sin embargo, no
hay nada en Python que garantice eso. ¿Qué sucedería si "a" es, digamos, un entero? ¿Y
si tengo una variable global llamada "x", terminará siendo usada dentro del bloque
"with"? Como puede ver, la naturaleza dinámica de Python complica mucho tales
decisiones.
funcion(args).dicc[indice][indice].a = 21
funcion(args).dicc[indice][indice].b = 42
funcion(args).dicc[indice][indice].c = 63
escriba esto:
ref = funcion(args).dict[indice][indice]
ref.a = 21
ref.b = 42
ref.c = 63
Los dos puntos son necesarios principalmente para mejorar la legibilidad (uno de los
resultados del lenguaje experimental ABC). Considere esto:
if a==b
print a
versus:
if a==b:
print a
Note como el segundo ejemplo es ligeramente más facil de leer. Incluso note como los
dos puntos comienzan el ejemplo en el primer párrafo de esta respuesta; es un uso
estándar en castellano.
Otra razón menor es que los dos puntos simplifican a los editores con resaltado de
sintáxis; pueden buscar los dos puntos para decidir cuando la sangría necesita
incrementarse en lugar de hacer un análisis más elaborado del texto del programa.