1   FAQ General de Python

Date:$Date: 2005-12-17 03:21:20 +0100 (Sat, 17 Dec 2005) $
Version:$Revision: 8684 $ (de la versión en Inglés 1.18)
Web site:http://www.python.org/

Contents

1.1   Información General

1.1.1   ¿Qué es Python?

Python es un lenguaje de programación interpretado, interactivo y orientado a objetos. Incorpora módulos, excepciones, tipado dinámico, tipos de datos dinámicos de muy alto nivel, y clases. Python combina un remarcable poder con una sintáxis muy clara. Tiene interfaces a muchas llamadas al sistema y bibliotecas, así como tambien a varios sistemas de ventanas, y es extensible en C o C++. También es utilizable como un lenguaje de extensión para aplicaciones que necesiten interfaces programables. Finalmente, Python es portable, corre en muchas variantes de Unix, en la Mac, y en PCs bajo MS-DOS, Windows, Windows NT, y OS/2.

Para descubrir más, comience con la Guía de Python para el Principiante.

1.1.2   En primer lugar, ¿por qué se creó Python?

Aquí hay un muy corto resumen de lo que lo comenzó todo, escrito por Guido van Rossum:

Tuve una amplia experiencia implementando un lenguaje interpretado en el grupo ABC en el CWI (N.T.: CWI es el Instituto Nacional de Investigación de Matemática y Ciencias de la Computación en Holanda), y de trabajar con este grupo aprendí mucho acerca del diseño de lenguajes. Este es el origen de muchas características de Python, incluyendo el uso de la sangría para agrupamiento de expresiones y la inclusión de tipos de datos de muy alto nivel (a pesar de que los detalles son todos diferentes en Python).

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.

Estaba trabajando en el grupo del sistema operativo distribuído Amoeba en el CWI. Necesitábamos una mejor manera de administrar el sistema que escribiendo programas en C o scripts en Bourne shell, ya que Amoeba tenía su propia interfaz que no era facilmente accesible desde el Bourne shell. Mi experiencia con el tratamiento de errores en Amoeba me hizo extremadamente consciente de la importancia de las excepciones como una característica de un lenguaje de programación.

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.

En Febrero de 1991, luego de un poco más de un año de desarrollo, decidí publicarlo en USENET. El resto está en el archivo Misc/HISTORY.

1.1.3   ¿Para qué es bueno Python?

Python es un lenguaje de programación de alto nivel y propósito general que puede aplicarse a muchos problemas de diferentes tipos.

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.

1.1.4   ¿Cómo trabaja el esquema de numeración de versiones de Python?

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.

No todos los lanzamientos son para corrección de errores. En la escalada a un nuevo lanzamiento principal, se hacen una serie de lanzamientos de desarrollo, denotadas como alfa, beta, o lanzamiento propuesto. Los alfas son lanzamientos tempranos dónde las interfaces no están aún terminadas; no es raro ver una interfaz cambiar entre dos lanzamientos alfa. Las betas son más estables, preservando las interfaces existentes pero posiblemente agregando nuevos módulos, y los lanzamientos propuestos se congelan, sin hacer cambios excepto los necesarios para corregir errores críticos.

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 CVS. En la práctica, luego de que se hizo un lanzamiento menor final, se incrementa el tronco CVS 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.

1.1.5   ¿Existen restricciones de derechos de autor en el uso de Python?

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.

1.1.6   ¿Cómo obtengo una copia del código fuente de Python?

La última distribución de fuentes de Python está siempre disponible en python.org, en http://www.python.org/download/. Las últimas fuentes de desarrollo pueden obtenerse por CVS anónimo en SourceForge, en http://www.sourceforge.net/projects/python.

La distribución de las fuentes es un archivo tar gzipeado que contiene el código C completo, la documentación LaTeX, los módulos de biblioteca de Python, programas ejemplo, y varios pedazos de software útil libremente distribuibles. Esto compilará y se ejecutará directamente en la mayoría de las plataformas UNIX.

Versiones más viejas de Python también están disponibles en python.org.

1.1.7   ¿Cómo obtengo documentación sobre Python?

Toda la documentación está disponible on-line, comenzando en http://www.python.org/doc.

La fuente LaTeX de la documentación es parte de la distribución fuente. Si usted no tiene LaTeX, el set con la última documentación de Python está disponible vía FTP anónimo en varios formatos como PostScript y HTML. Visite el URL de arriba para enlaces a las versiones actuales.

1.1.8   Nunca programé antes. ¿Hay un tutorial 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.

1.1.10   ¿Hay un grupo de noticias o lista de correo dedicada a Python?

Hay un grupo de noticias, comp.lang.python, y una lista de correo, python-list. El grupo de noticias y la lista de correo están interrelacionadas -- si puede leer noticias, no es necesario que se subscriba a la lista de correo. comp.lang.python tiene mucho tráfico, recibiendo cientos de mensajes todos los días, y los lectores Usenet normalmente son más capaces de hacer frente a este volumen.

Los anuncios de lanzamientos de nuevo software y eventos pueden encontrarse en comp.lang.python.announce, una lista moderada de bajo tráfico que recibe algo de cinco mensajes por día. Está disponible como la lista de correo python-announce.

Puede encontrarse más información acerca de otras listas de correo y grupos de noticias en http://www.python.org/community/lists.html.

1.1.11   ¿Cómo obtengo una versión de prueba beta de Python?

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.

Tambien puede acceder a la versión de desarrollo de Python a través de CVS. Vea http://sourceforge.net/cvs/?group_id=5470 para detalles. Si no está familiarizado con CVS, documentos como http://linux.oreillynet.com/pub/a/linux/2002/01/03/cvs_intro.html dan una introducción.

1.1.12   ¿Cómo envío reportes de error y parches para Python?

Para reportar un error o enviar un parche, por favor use el servicio correspondiente en el proyecto Python en SourceForge.

Errores: http://sourceforge.net/tracker/?group_id=5470&atid=105470

Parches: http://sourceforge.net/tracker/?group_id=5470&atid=305470

Debe tener un usuario en SourceForge para reportar errores; esto nos permite contactarlo si tenemos algunas preguntas. Tambien le permite a SourceForge enviarle actualizaciones cuando trabajamos en su error.

Para más información de como es desarrollado Python, consulte la Guía del Desarrollador de Python.

1.1.13   ¿Hay publicado algún artículo sobre Python al que pueda hacer referencia?

Probablemente sea mejor hacer referencia a su libro favorito sobre Python.

El primerísimo artículo sobre Python es este, muy viejo y bastante caduco:

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.
1.1.14   ¿Hay libros sobre Python?

Si, hay muchos y más están siendo publicados. Vea la lista en el Wiki de python.org en http://www.python.org/cgi-bin/moinmoin/PythonBooks.

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".

1.1.15   ¿Dónde está www.python.org ubicado mundialmente?

Actualmente está en Amsterdam, gentilmente servido por XS4ALL. Gracias a Thomas Wouters por su trabajo en disponer el servidor de python.org.

1.1.16   ¿Por qué se llama Python?

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.

1.2   Python en el mundo real

1.2.1   ¿Cuán estable es Python?

Muy estable. Lanzamientos estables, nuevos, han estado saliendo aproximadamente cada 6 a 18 meses desde 1991, y esto parece continuar así. Actualmente hay normalmente algo de 18 meses entre lanzamientos principales.

Con la introducción de lanzamientos retrospectivos con corrección de errores, la estabilidad de las versiones existentes está siendo mejorada. Los lanzamientos de corrección de errores, indicados por un tercer componente en el número de versión (ej. 2.1.3, 2.2.2), son administrados para la estabilidad; solamente correcciones a problemas conocidos son incluídos en un lanzamiento de corrección de errores, y está garantizado que las interfaces permanecerán iguales con el transcurso de este tipo de lanzamientos.

La versión 2.3.3 es la más estable en este momento.

1.2.2   ¿Cuánta gente está usando Python?

Probablemente decenas de miles de usuarios, es complicado obtener un conteo exacto. Python está disponible para bajar gratis, por lo que no hay cifras de ventas, y está disponible en muchos sitios diferentes e incluído en muchas distribuciones Linux, por lo que las estadísticas de bajadas no cuentan tampoco la historia completa. El grupo de correo comp.lang.python es muy activo, pero no todos los usuarios envían mensajes al grupo o incluso lo leen. En general, no hay una estimación precisa del número de abonados o usuarios Python.

1.2.3   ¿Se han hecho proyectos significativos en Python?

Vea http://www.pythonology.org/success para una lista de proyectos que usan Python. Consultar los procesos de conferencias Python del pasado revelará contribuciones de muchas organizaciones y compañías diferentes.

Proyectos Python de alto nivel incluyen el administrador de listas de correo Mailman y el servidor de aplicaciones Zope. Muchas distribuciones Linux, la más notable es Red Hat, escribieron parte de, o todo su instalador y software de administración del sistema, en Python. Algunas compañías que usan Python internamente son Google, Yahoo, e Industrial Light & Magic.

1.2.4   ¿Qué nuevos desarrollos se esperan para Python en el futuro?

Vea http://www.python.org/peps para las Propuestas de Mejoras de Python (PEPs en inglés). Las PEP son documentos de diseño que describen una nueva característica sugerida para Python, proveyendo una especificación técnica concisa y un análisis razonado.

PEP 1 explica el proceso de las PEP y su formato; léalo primero si quiere proponer una PEP.

Los nuevos desarrollos se discuten en la lista de correo python-dev.

1.2.5   ¿Es razonable proponer cambios incompatibles a Python?

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.

Es necesario proveer un camino de mejora gradual si se debe cambiar una característica. La PEP 5 describe el procedimiento seguido para introducir cambios incompatibles con lo anterior minimizando la interferencia a los usuarios.

1.2.6   ¿Qué es la Python Software Foundation?

La Python Software Foundation es una organización independiente sin fines de lucro que posee los derechos de autor de las versiones 2.1 y más nuevas de Python. La misión de PSF es hacer progresos en tecnología de código abierto relacionada al lenguaje de programación Python y difundir el uso de Python. La página principal de PSF está en http://www.python.org/psf/.

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.

1.2.7   ¿Está Python preparado para Y2K (año 2000)?

Para Agosto de 2003, no se reportó ningún problema importante y la conformidad a Y2K no parece ser un inconveniente.

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:

  1. 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.
  2. 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.

1.2.8   ¿Python es un buen lenguaje para programadores que recién comienzan?

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.

El intérprete interactivo de Python le permite a los estudiantes probar características del lenguaje mientras están programando. Pueden mantener una ventana abierta con el intérprete ejecutándose mientras ingresan el código de su programa en otra ventana. Si no pueden recordar los métodos de una lista, pueden hacer algo como esto:

>>> 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.

1.3   Actualizando Python

1.3.1   ¿Qué es este módulo bsddb185 del que se queja mi aplicación?

Desde Python 2.3, la distribución incluye el paquete PyBSDDB <http://pybsddb.sf.net/> como un reemplazo del viejo módulo bsddb. Incluye funciones que proveen compatibilidad para atrás al nivel de API (N.T.: API es Interfaz Programa Aplicación), pero necesita una versión más nueva de la biblioteca subyacente Berkeley DB. Los archivos creados con el módulo más viejo bsddb no pueden abrirse directamente con el módulo nuevo.

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:

python2.2 <camino>/db2pickley.py database.db database.pck

Renombre su archivo de base de datos:

mv database.db olddatabase.db

Ahora convierta el archivo pickle al nuevo formato de base de datos:

python2.3 <camino>/pickle2db.py database.db database.pck

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.

1.4   Diseño de Python

1.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.

Ya que no hay llaves de comienzo/fin, no puede haber desacuerdos entre los agrupamientos percibidos por el analizador y el lector humano. Ocasionalmente, los programadores C encuentran un fragmento de código como este:

if (x <= y)
        x++;
        y--;
z++;

Solamente la expresión x++ es ejecutada si la condición es verdadera, pero al sangría le lleva a creer otra cosa. Incluso programadores experimentados de C se quedarán algunas veces mirándolo un largo rato y preguntándose por qué se decrementa y incluso para x > y.

Ya que no hay llaves de comienzo/fin, Python es mucho menos propenso a conflictos de estilo de código. En C hay muchas maneras diferentes de ubicar las llaves. Si está acostumbrado a leer y escribir código que usa un estilo, se sentirá por lo menos incómodo cuando lea (o se necesite que escriba) otro estilo.

Muchos estilos de código ubican las llaves de comienzo/fin en una linea por si mismos. Esto hace a los programas considerablemente más largos y desperdicia valioso espacio de pantalla, haciendo más dificil tener una buena vista general del programa. Idealmente, una función debería caber en una pantalla (digamos, 20-30 líneas). 20 líneas de Python pueden hacer mucho más trabajo que 20 líneas de C. Esto no es solamente debido a la ausencia de llaves de comienzo/fin -- la falta de declaraciones y los tipos de datos de alto nivel también son responsables -- pero la sintáxis basada en sangrías ciertamente ayuda.

1.4.2   ¿Por qué los cálculos de punto flotante son tan inexactos?

La gente normalmente se sorprende por resultados como este:

>>> 1.2-1.0
0.199999999999999996

y piensa que es una falla en Python. No lo es. Es un problema causado por la representación interna de los números de punto flotante, los cuales usan un número fijo de dígitos binarios para representar un número decimal. Algunos números decimales no pueden representarse exactamente en binario, lo que resulta en pequeños errores de redondeo.

En matemática decimal, hay muchos números que no pueden representarse con un número fijo de dígitos decimales, ej. 1/3 = 0.3333333333.......

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.

Una de las consecuencias de esto es que es peligroso comparar el resultado de algunos cálculos a un flotante con ==. Pequeñas imprecisiones pueden significar que == falle. En cambio, usted debe controlar que la diferencia entre los dos números sea menor que un cierto límite:

epsilon = 0.0000000000001 # pequeño error permitido
resultado_esperado = 0.4

if resultado_esperado-epsilon <= calculo() <= resultado_esperado+epsilon:
   ...

Por favor consulte el capítulo sobre aritmética de punto flotante en el tutorial de Python para más información.

1.4.3   ¿Por qué las cadenas de caracteres de Python son inmutables?

Existen varias ventajas.

Una es la performance: sabiendo que una cadena es inmutable facilita la disposición en tiempo de construcción, ya que las necesidades de almacenamiento son fijas y estáticas. Esta es también una de las razones para la distinción entre tuplas y listas.

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.

1.4.4   ¿Por qué se debe explicitar 'self' en las llamadas y definiciones de métodos?

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.

Segundo, significa que no se necesita una sintáxis especial si quiere explícitamente referenciar o llamar a un método de una clase en particular. En C++, si quiere usar un método de la clase base el cual está redefinido en una clase derivada, tiene que usar el operador :: -- en Python puede escribir clase_base.nombre_metodo(self, <lista de argumentos>). Esto es particularmente útil para los métodos __init__(), y en general en casos donde un método de una clase derivada quiere extender el método de la clase base del mismo nombre y por lo tanto tiene que llamar de alguna manera al método de la clase base.

Finalmente, para variables de instancia soluciona un problema sintáctico con la asignación: ya que en Python las variables locales son (¡por definición!) aquellas variables a las cuales se les asigna un valor en el cuerpo de una función (y que no son explicitamente declaradas como globales), tiene que haber alguna manera de decirle al intérprete que una asignación pretendía asignar a una variable de instancia en lugar de a una variable local, y esta manera preferentemente debería ser sintáctica (por razones de eficiencia). C++ hace esto con declaraciones, pero Python no tiene declaraciones y sería una pena tener que introducirlas solamente para este propósito. Usar el "self.var" explícito resuelve esto de manera elegante. De la misma manera, para usar variables de instancia, tener que escribir "self.var" significa que las referencias a nombres no calificados dentro de un método no obliga a buscar en los directorios de la instancia.

1.4.5   ¿Por qué no puedo usar una asignación en una expresión?

Mucha gente acostumbrada a C o Perl se queja de que ellos quieren usar este modismo:

while (linea = readline(f)) {
    ...hacer algo con linea...
}

cuando en Python están obligados a escribir esto:

while True:
    linea = f.readline()
    if not linea:
        break
    ...hacer algo con linea...

La razón para no permitir la asignación en las expresiones de Python, es un bug común pero dificil de encontrar en esos otros lenguajes, causados por esta construcción:

if (x = 0) {
    ...manejo de errores...
}
else {
    ...código que sólo trabaja para x no cero...
}

El error es solamente tipográfico: x = 0, el cual asigna 0 a la variable x, fue escrito mientras que la comparación x == 0 era lo que ciertamente se pretendía.

Se propusieron muchas alternativas. La mayoría son alteraciones que ahorran algo de tipeo pero usan palabras claves o sintáxis críptica o arbitraria, y fallan en el criterio simple para las propuestas de cambio del lenguaje: deben intuitivamente sugerir el significado correcto a un lector humano al cual no se le explicó la construcción.

Un fenómeno interesante es que la mayoría de los programadores experimentados de Python reconocen el modismo "while True" y no parece que extrañen mucho la asignación en una expresión; sólo los recién llegados son quienes expresan un fuerte deseo de agregar esto al lenguaje.

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.

La mejor aproximación es usar iteradores, haciendo posible realizar lazos a través de objetos con la declaración for. Por ejemplo, en la versión actual de Python los objetos de archivo soportan el protocolo de iteración, de manera que usted puede simplemente escribir:

for linea in f:
    ...hacer algo con linea...
1.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).

De hecho, implementar len(), max(), min() como una función integrada es actualmente menos código que implementarlas como métodos para cada tipo. Uno puede dudar en los casos puntuales pero es una parte de Python, y es demasiado tarde ahora para esos cambios tan fundamentales. Las funciones tienen que permanecer para evitar una rotura masiva de código.

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.

1.4.7   ¿Por qué join() es un método de cadena en lugar de un método de lista o tupla?

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:

", ".join(['1', '2', '4', '8', '16'])

el cual tiene como resultado:

"1, 2, 4, 8, 16"

Hay dos argumentos usuales contra este uso.

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.

La segunda objeción es tipicamente hecha como: "Realmente le estoy diciendo a una secuencia que una sus miembros entre sí con una constante de cadena". Tristemente, no están haciendo eso. Por alguna razón parece haber mucha menos dificultad en tener split() como un método de cadena, ya que en ese caso es facil ver que:

"1, 2, 4, 8, 16".split(", ")

instruye a un literal de cadena a devolver las subcadenas delimitadas por el separador dado (o, por defecto, corridas arbitrarias de espacio en blanco). En este caso una cadena Unicode devuelve una lista de cadenas Unicode, una cadena ASCII devuelve una lista de cadenas ASCII, y todos son felices.

join() es un método de cadena porque al usarlo le está diciendo a la cadena separadora que itere sobre una secuencia arbitraria, formando representaciones de cadena de cada uno de los elementos, e insertándose a si misma entre las representaciones de los elementos. Este método puede usarse con cualquier argumento que obedezca las reglas para objetos de secuencia, incluyendo cualesquiera nuevas clases que desee definir usted mismo.

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.

Si ninguno de estos argumentos lo convence, entonces por el momento puede seguir utilizando la función join() del módulo string, el cual le permite escribir:

string.join(['1', '2', '4', '8', '16'], ", ")
1.4.8   ¿Cuán rápidas son las excepciones?

Un bloque try/except es extremadamente eficiente. Actualmente, ejecutar una excepción es caro. En versiones de Python anteriores a la 2.0 era común usar este modismo:

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)).)

1.4.9   ¿Por qué no hay una expresión switch o case en Python?

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:

def funcion_1 (...):
        ...

funciones = {'a': funcion_1,
             'b': funcion_2, 
             'c': self.metodo_1, ...}

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:

def visita_a (self, ...):
    ...
...

def despachar (self, valor):
    nombre_metodo = 'visita_' + str(valor)
    metodo = getattr(self, nombre_metodo)
    metodo()

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.

1.4.10   ¿No pueden emular hilos en el intérprete en lugar de usar la implementación específica del S.O.?

Respuesta 1: Desafortunadamente, el intérprete empuja al menos un cuadro de pila de C por cada cuadro de pila de Python. También, las extensiones pueden llamar de vuelta a Python en cualquier momento casi al azar. Por lo tanto, una implementación completa de hilos requiere soporte de hilos para C.

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.

1.4.11   ¿Por qué las formas lambda no pueden contener expresiones?

Las formas lambda de Python no pueden contener expresiones porque el esquema sintáctico de Python no puede manejar expresiones anidadas. Sin embargo, en Python, esto no es un problema serio. A diferencia de las formas lambda en otros lenguajes, donde añaden funcionalidad, las lambdas de Python son solamente un atajo si se es demasiado perezoso para definir una función.

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!).

1.4.12   ¿Puede compilarse Python a código de máquina, C o algún otro lenguaje?

No facilmente. Los tipos de datos de alto nivel, objetos de tipado dinámico y la invocación del intérprete en momento de ejecución (usando eval() o exec) en Python, implican que un programa "compilado" de Python probablemente consistiría principalmente en llamadas al sistema de ejecución de Python, incluso para operaciones aparentemente sencillas como x+1.

Muchos proyectos descriptos en los grupos de Python o en pasadas conferencias de Python han demostrado que este acercamiento es factible, a pesar que las mejoras alcanzadas en velocidad hasta ahora son sólo modestas (ej. 2x). Jython usa la misma estrategia para compilar a código de byte de Java. (Jim Hugunin ha demostrado que en combinación con un análisis completo del programa, mejoras de 1000x son factibles para pequeños programas de demostración. Vea los procesos de la conferencia Python de 1997 para más información.)

Internamente, el código fuente de Python siempre se traduce a una representación de código de byte, y este código se ejecuta luego en la máquina virtual de Python. De manera de evitar analizar y traducir repetidas veces módulos que raramente cambian, este código de byte es escrito en un archivo cuyo nombre termina en ".pyc" ubicado en el lugar donde se analiza el módulo. Cuando se modifica el archivo ".py" correspondiente, se analiza y traduce nuevamente y se reescribe el archivo .pyc.

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.

1.4.13   ¿Cómo maneja Python la memoria?

Los detalles de la administración de la memoria de Python dependen de la implementación. La implementación de Python de C estándar usa el conteo de referencias para detectar objetos inaccesibles, y otro mecanismo para juntar lazos de referencias, ejecutando periodicamente un algoritmo de detección de lazos que busca lazos inaccesibles y borra los objetos allí involucrados. El módulo gc provee funciones para realizar una recolección de basura, obtener estadísticas de depuración, y afinar los parámetros del recolector.

Jython se basa en la ejecución de Java, por lo que se usa el recolector de basura de la máquina virtual de Java (JVM). Esta diferencia puede originar algunos sutiles problemas al portar su código Python si este depende del comportamiento de la implementación del conteo de referencias.

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).

En ausencia de circularidades y trazas de retorno, los programas en Python no necesitan manejar la memoria explícitamente.

¿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.)

La recolección de basura (GC) tradicional también se vuelve un problema cuando se integra Python en otras aplicaciones. Mientras que en un Python independiente está bien reemplazar el malloc() y el free() estándar con versiones provistas por la biblioteca de GC, una aplicación que integra Python quizás quiera tener su propio substituto para malloc() y free(), y no quiera el de Python. Actualmente, Python trabaja con todo lo que implemente adecuadamente malloc() y free().

En Jython, el siguiente código (el cual es correcto en CPython) probablemente agotará los descriptores de archivos mucho antes de que se agote la memoria:

for archivo in <lista de archivos muy larga>:
    f = open(archivo)
    c = f.read(1)

Usando el esquema actual de conteo de referencia y destructor, cada nueva asignación a f cierra el archivo anterior. Usando GC, esto no se garantiza. Si quiere escribir código que trabaje con cualquier implementación de Python, debería explicitamente cerrar el archivo; esto trabajará sin importar el GC:

for archivo in <lista de archivos muy larga>:
    f = open(archivo)
    c = f.read(1)
    f.close()
1.4.14   ¿Porque no se libera toda la memoria cuando termina Python?

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.

1.4.15   ¿Por qué hay tipos de datos tuplas y listas separados?

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.

1.4.16   ¿Cómo se implementan 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.

Cuando se agregan o insertan items, el arreglo de referencias cambia de tamaño. Algo de inteligencia se aplica para mejorar la performance de agregar items repetidamente; cuando se debe agrandar el arreglo, se ubica algo de espacio extra de manera que no se necesite un cambio de tamaño algunas de las próximas veces.

1.4.17   ¿Como se implementan los diccionarios?

Los diccionarios de Python se implementan como tablas hash de tamaño variable. Comparados con los B-trees, esto da una mejor performance para la búsqueda (la operación más común por lejos) en la mayoría de los casos, y la implementación es más simple.

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.

1.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.

Algunas soluciones no aceptables que fueron propuestas:

  • 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.

Más aún, debe siempre ser el caso de que si o1 == o2 (ej: o1.__cmp__(o2)==0) entonces hash(o1)==hash(o2) (ej: o1.__hash__() == o2.__hash__()), sin importar si el objeto es un diccionario o no. Si usted falla en lograr estas restricciones, los diccionarios y otras estructuras basadas en hash tendrán un comportamiento anómalo.

En el caso de EnvuelveLista, mientras el objeto envolvente esté en un diccionario, la lista envuelta no debe cambiar para prevenir anomalías. No haga esto a menos que esté preparado para pensar mucho acerca de los requerimientos y las consecuencias de no lograrlos correctamente. Considérese avisado.

1.4.19   ¿Por qué list.sort() no devuelve la lista ordenada?

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]...
1.4.20   ¿Cómo se detalla y refuerza una especificación de interfaz en Python?

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.

Un buen conjunto de pruebas para un módulo puede proveer simultaneamente una prueba de regresión, servir como especificación de la interfaz del módulo y conjunto de ejemplos. Muchos módulos Python pueden ejecutarse como programas para proveer un simple "autotest". Incluso módulos que usan complejas interfaces externas pueden frecuentemente ser probadas en aislación usando las triviales emulaciones "stub" de la interfaz externa. Los módulos doctest y unittest o marcos de trabajo de prueba de terceros pueden usarse para construir conjuntos de pruebas exhaustivos que ejercitan cada linea de código en un módulo.

Una apropiada disciplina de pruebas puede ayudar a construir grandes y complejas aplicaciones en Python tanto como lo harían especificaciones de interfaces. De hecho, puede ser mejor, porque una especificación de interfaz no puede probar ciertas propiedades de un programa. Por ejemplo, se espera que el método append() agregue nuevos elementos al final de una lista interna; una especificación de interfaz no puede probar que su implementación de append() haga esto correctamente, pero es trivial probarlo en un conjunto de pruebas.

Escribir conjuntos de pruebas es de mucha ayuda, y quizás quiera diseñar su código prestando atención en hacer que se pueda probar fácil. Una técnica cada vez más popular, el desarrollo dirigido a pruebas, implica escribir partes del conjunto de pruebas primero, antes de escribir el código real. Por supuesto, Python le permite ser descuidado y no escribir para nada los casos de prueba.

1.4.21   ¿Por qué los valores por defecto son compartidos entre los objetos?

Este tipo de error normalmente es cometido por programadores neófitos. Considere esta función:

def foo(D={}):  # Peligro: referencia a un diccionario compartida para todas las llamadas
    ... calcular algo ...
    D[clave] = valor
    return D

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.

Gracias a esta característica, es una buena práctica de programación el no usar objetos mutables como valores por defecto. En cambio, use None como valor por defecto, y dentro de la función controle si el parámetro es None, y si lo es cree una nueva lista/diccionario/lo-que-sea. Por ejemplo, no escriba:

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í:

# Los llamantes nunca pasarán un tercer parámetro a esta función.
def muycara (arg1, arg2, _cache={}):
    if _cache.has_key((arg1, arg2)):
        return _cache[(arg1, arg2)]

# 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.

1.4.22   ¿Por qué no hay goto?

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:

class etiqueta: pass # declara una etiqueta

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.

1.4.23   ¿Por qué obtengo un SyntaxError por un 'continue' dentro de un 'try'?

Esto es una limitación de implementación, causada por la manera extremadamente sencilla en que Python genera el código de byte. El bloque try inserta algo en la "pila de bloque" que el continue debería retirar nuevamente. El generador de código actual no tiene las estructuras de datos de manera que el continue pueda generar el código correcto.

¡Note que Jython no tiene esta restricción!

1.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:

f = open("/mydir/file.txt") # trabaja bien!

Si está intentando construir un camino de directorio para una órden de DOS, pruebe como en uno de los siguientes ejemplos:

dir = r"\este\es\mi\dir\de\dos" "\\"
dir = r"\este\es\mi\dir\de\dos\ "[:-1]
dir = "\\este\\es\\mi\\dir\\de\\dos\\"
1.4.25   ¿Por qué Python no tiene una expresión "with" como otros lenguajes?

Porque tal construcción sería ambigua.

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.

Por ejemplo, fíjese en el siguiente ejemplo incompleto:

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.

El beneficio primario del "with" y características similares del lenguaje (reducción de cantidad de código) pueden, sin embargo, conseguirse facilmente en Python con la asignación. En lugar de

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

Esto también tiene el efecto colateral de incrementar la velocidad de ejecución porque los vínculos de nombres se resuelven en tiempo de ejecución en Python, y la segunda versión necesita ejecutar la resolución una sola vez. Por supuesto, si el objeto referenciado no tiene los atributos a, b y c, el resultado final es una excepción en tiempo de ejecución.

1.4.26   ¿Por qué se necesitan dos puntos para las expresiones if/while/def/class?

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.