You are on page 1of 25

1 Información General

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 sintaxis muy clara. Tiene
interfaces a muchas llamadas al sistema y bibliotecas, así como también 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.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.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.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 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.

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.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 Subversion anónimo en http://svn.python.org/projects/python/trunk

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.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.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.9 ¿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.10 ¿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 Subversion.


Vea http://www.python.org/dev/faq/#subversion-svn para detalles.

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

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.

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


Desarrollador de Python.

1.12 ¿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.13 ¿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.14 ¿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.15 ¿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.16 ¿Me tiene que gustar "Monty Python's Flying Circus"?

No, pero ayuda. :)

2 Python en el mundo real


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.

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.
2.3 ¿Se han hecho proyectos significativos en Python?

Vea http://python.org/about/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.

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.

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.

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.

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:

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.

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.

3 Actualizando Python
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.

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.

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.

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.

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.

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.

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

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.

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'], ", ")

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

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.

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

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.

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

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.

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.

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.

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.

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

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

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.

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!

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

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.

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.

Website maintained by the Python community


hosting by xs4all / design by Tim Parkin
Copyright © 1990-2010, Python Software Foundation
Legal Statements

You might also like