Python Tutorial Parra
Python Tutorial Parra
Tutorial Oficial
de Python 3.1x
Extraído de: https://docs.python.org/es/3/
.
(Editado y Compilado por Diego Parrás)
Para los que aún no lo conocen, Python es un lenguaje de programación creado por
Guido van Rossum en 1991, que se ha convertido en uno de los más populares del mundo, sobre
todo en el ámbito de las organizaciones. Python destaca por su legibilidad, simplicidad y
versatilidad. Esto lo convierte en un excelente lenguaje tanto para los que apenas comienzan en
el mundo de la programación como para los programadores experimentados que buscan mayor
eficiencia y flexibilidad.
Para una descripción de los objetos estándar y de los módulos, ver La biblioteca
estándar de Python. Referencia del Lenguaje Python dónde se ofrece una definición más
formal del lenguaje. Para escribir extensiones en C o C++, leer Ampliación e incrustación
del intérprete de Python y Manual de referencia de la API en C de Python. Existen
diversos libros que cubren Python en detalle.
Este tutorial no pretende ser exhaustivo ni cubrir cada una de las características
del lenguaje, ni siquiera las más utilizadas. En vez de eso, pretende introducir muchas
de las funcionalidades más notables y brindar una idea clara acerca del estilo y el tipo
de lenguaje que es Python. Después de leerlo podrás leer y escribir módulos y programas
en Python, y estarás listo para aprender más acerca de las diversas librerías y módulos
descritos en La biblioteca estándar de Python.
Puedes escribir un script de shell de Unix o archivos por lotes de Windows para
algunas de estas tareas. Los scripts de shell son mejores para mover archivos y cambiar
datos de texto, pero no son adecuados para juegos o aplicaciones GUI. Podrías escribir
un programa C / C ++ / Java, pero llevaría mucho tiempo de desarrollo obtener incluso
un primer programa de borrador. Python es más fácil de usar, está disponible en los
sistemas operativos Windows, macOS y Unix, y te ayudará a hacer el trabajo más
rápidamente.
• los tipos de datos de alto nivel permiten expresar operaciones complejas en una
sola instrucción;
• la agrupación de instrucciones se hace mediante indentación en vez de llaves de
apertura y cierre;
• no es necesario declarar variables ni argumentos.
Ahora que estás emocionado con Python, querrás verlo en más detalle. Como la
mejor forma de aprender un lenguaje es usarlo, el tutorial te invita a que juegues con el
intérprete de Python a medida que vas leyendo.
El resto del tutorial introduce varias características del lenguaje y el sistema Python
a través de ejemplos, empezando con expresiones, instrucciones y tipos de datos
simples, pasando por funciones y módulos, y finalmente tocando conceptos avanzados
como excepciones y clases definidas por el usuario.
python3.11
en el terminal 1. Ya que la elección del directorio dónde vivirá el intérprete es una opción
del proceso de instalación, puede estar en otros lugares; consulta a tu gurú de Python
local o administrador de sistemas. (Por ejemplo, /usr/local/python es una
alternativa popular).
En máquinas con Windows en las que haya instalado Python desde Microsoft
Store, el comando python3.11 estará disponible. Si tiene el lanzador py.exe instalado,
puede usar el comando py. Consulte Excurso: configurar variables de entorno para
conocer otras formas de iniciar Python.
Se puede salir del intérprete con estado de salida cero ingresando el carácter de
fin de archivo (Control-D en Unix, Control-Z en Windows). Si eso no funciona, puedes
salir del intérprete escribiendo el comando: quit().
Algunos módulos de Python también son útiles como scripts. Estos pueden
invocarse utilizando python -m módulo [arg] ..., que ejecuta el archivo fuente
para módulo como si se hubiera escrito el nombre completo en la línea de comandos.
Cuando se usa un script, a veces es útil poder ejecutar el script y luego ingresar al
modo interactivo. Esto se puede hacer pasando la -i antes del nombre del script.
$ python3.11
Python 3.11 (default, April 4 2021, 09:25:04)
[GCC 10.2.0] on linux
Type "help", "copyright", "credits" or "license" for more
information.
Las líneas de continuación son necesarias cuando se ingresa una construcción multilínea.
Como ejemplo, echa un vistazo a la sentencia if:
Para declarar una codificación que no sea la predeterminada, se debe agregar una
línea de comentario especial como la primera línea del archivo. La sintaxis es la
siguiente:
Una excepción a la regla de primera línea es cuando el código fuente comienza con
una linea UNIX «shebang». En ese caso, la declaración de codificación debe agregarse
como la segunda línea del archivo. Por ejemplo:
Notas al pie
1 En Unix, el intérprete de Python 3.x no está instalado por defecto con el ejecutable
llamado python, por lo que no entra en conflicto con un ejecutable de Python 2.x
instalado simultáneamente.
Algunos ejemplos:
3.1.1. Números
El intérprete actúa como una calculadora simple: puede escribir una expresión en ella y
escribirá el valor. La sintaxis de la expresión es sencilla: los operadores+, -, * y / se
pueden usar para realizar aritmética; Los paréntesis (()) se puede utilizar para agrupar.
Por ejemplo:
>>> 2 + 2
Los números enteros (ej. 2, 4, 20) tienen tipo int, los que tienen una parte
fraccionaria (por ejemplo 5.0, 1.6) tiene el tipo float. Vamos a ver más acerca de los
tipos numéricos más adelante en el tutorial.
La división (/) siempre retorna un número decimal de punto flotante. Para hacer
floor division y obtener un número entero como resultado puede usarse el operador //;
para calcular el resto puedes usar %:
>>> 5 ** 2 # 5 squared
25
>>> 2 ** 7 # 2 to the power of 7
128
El signo igual (=) se usa para asignar un valor a una variable. Después, no se
muestra ningún resultado antes del siguiente prompt interactivo:
>>> width = 20
>>> height = 5 * 9
>>> width * height
900
>>> 4 * 3.75 - 1
14.0
Esta variable debe ser tratada como de sólo lectura por el usuario. No le asignes
explícitamente un valor; crearás una variable local independiente con el mismo nombre
enmascarando la variable con el comportamiento mágico.
Además de int y float, Python admite otros tipos de números, como Decimal
y Fraction. Python también tiene soporte incorporado para complex numbers, y usa
el sufijo j o J para indicar la parte imaginaria (por ejemplo, 3+5j).
3.1.2. Texto
Python puede manipular texto (representado por el tipo str, las llamadas
«cadenas»), así como números. Esto incluye personajes «!», palabras «conejo»,
nombres «París», frases «Got your back.», etc. «¡Yay! :)». Pueden incluirse
entre comillas simples ('...') o comillas dobles ("...") con el mismo resultado 2.
>>> "Paris rabbit got your back :)! Yay!" # double quotes
Hay un aspecto sutil de las cadenas sin formato: una cadena sin formato puede no
terminar en un número impar de \ caracteres; consulte la entrada de preguntas
frecuentes para obtener más información y soluciones alternativas.
Las cadenas de texto literales pueden contener múltiples líneas. Una forma es usar
triples comillas: """...""" o '''...'''. Los fin de línea son incluidos
automáticamente, pero es posible prevenir esto agregando una \ al final de la línea. Por
ejemplo:
print("""\
Usage: thingy [OPTIONS]
-h Display this usage message
-H hostname Hostname to connect to
""")
produce la siguiente salida (tener en cuenta que la línea inicial no está incluida):
Dos o más cadenas literales (es decir, las encerradas entre comillas) una al lado de
la otra se concatena automáticamente.
Los índices también pueden ser números negativos, para empezar a contar desde
la derecha:
Nótese que -0 es lo mismo que 0, los índice negativos comienzan desde -1.
Además de los índices, las rebanadas también están soportadas. Mientras que los
índices se utilizar para obtener caracteres individuales, las rebanadas te permiten
obtener partes de las cadenas de texto:
Los índices de las rebanadas tienen valores por defecto útiles; el valor por defecto
para el primer índice es cero, el valor por defecto para el segundo índice es la longitud
de la cadena a rebanar.
Nótese cómo el inicio siempre se incluye y el final siempre se excluye. Esto asegura
que s[:i] + s[i:] siempre sea igual a s:
Una forma de recordar cómo funcionan las rebanadas es pensar que los índices
apuntan entre caracteres, con el borde izquierdo del primer carácter numerado 0.
+---+---+---+---+---+---+
| P | y | t | h | o | n |
+---+---+---+---+---+---+
0 1 2 3 4 5 6
-6 -5 -4 -3 -2 -1
>>> word[4:42]
'on'
>>> word[42:]
''
Las cadenas de Python no se pueden modificar, son immutables. Por eso, asignar
a una posición indexada de la cadena resulta en un error:
>>> s = 'supercalifragilisticexpialidocious'
>>> len(s)
34
Ver también
Cadenas de caracteres — str
Las cadenas de texto son ejemplos de tipos secuencias y soportan las operaciones
comunes para esos tipos.
Métodos de las cadenas de caracteres
Las cadenas de texto soportan una gran cantidad de métodos para transformaciones
básicas y búsqueda.
Literales de cadena formateados
Literales de cadena que tienen expresiones embebidas.
Sintaxis de formateo de cadena
Aquí se da información sobre formateo de cadenas de texto con str.format().
Formateo de cadenas al estilo *printf*
Aquí se describen con más detalle las antiguas operaciones para formateo utilizadas
cuando una cadena de texto está a la izquierda del operador %.
3.1.3. Listas
Python tiene varios tipos de datos compuestos, utilizados para agrupar otros
valores. El más versátil es la lista, la cual puede ser escrita como una lista de valores
separados por coma (ítems) entre corchetes. Las listas pueden contener ítems de
diferentes tipos, pero usualmente los ítems son del mismo tipo.
Al igual que las cadenas (y todas las demás tipos integrados sequence), las listas
se pueden indexar y segmentar:
Todas las operaciones de rebanado retornan una nueva lista que contiene los
elementos pedidos. Esto significa que la siguiente rebanada retorna una shallow copy
de la lista:
>>> squares[:]
[1, 4, 9, 16, 25]
A diferencia de las cadenas, que son immutables, las listas son de tipo mutable, es
decir, es posible cambiar su contenido:
Es posible anidar listas (crear listas que contengan otras listas), por ejemplo:
Por supuesto, podemos usar Python para tareas más complicadas que sumar
dos más dos. Por ejemplo, podemos escribir una parte inicial de la serie de Fibonacci así:
>>> i = 256*256
>>> print('The value of i is', i)
The value of i is 65536
El parámetro nombrado end puede usarse para evitar el salto de linea al final de
la salida, o terminar la salida con una cadena diferente:
>>> a, b = 0, 1
>>> while a < 1000:
... print(a, end=',')
... a, b = b, a+b
...
0,1,1,2,3,5,8,13,21,34,55,89,144,233,377,610,987,
Notas al pie
1 Debido a que ** tiene una prioridad mayor que -, -3**2 se interpretará como -
(3**2), por lo tanto dará como resultado -9. Para evitar esto y obtener 9, puedes usar
(-3)**2.
4.1. La sentencia if
Tal vez el tipo más conocido de sentencia sea el if. Por ejemplo:
Puede haber cero o más bloques elif, y el bloque else es opcional. La palabra
reservada elif es una abreviación de “else if”, y es útil para evitar un sangrado
excesivo.
Código que modifica una colección mientras se itera sobre la misma colección
puede ser complejo de hacer bien. Sin embargo, suele ser más directo iterar sobre una
copia de la colección o crear una nueva colección:
3
4
Para iterar sobre los índices de una secuencia, puedes combinar range() y
len() así:
En la mayoría de los casos, sin embargo, conviene usar la función enumerate(), ver
online Técnicas de iteración.
>>> range(10)
range(0, 10)
Decimos que tal objeto es iterable; esto es, que se puede usar en funciones y
construcciones que esperan algo de lo cual obtener ítems sucesivos hasta que se
>>> sum(range(4)) # 0 + 1 + 2 + 3
6
Más adelante veremos otras funciones que aceptan iterables cómo argumentos
o retornan iterables. En el capítulo Estructuras de datos, discutiremos en más detalle
sobre la list().
La declaración break rompe el bucle interno del for o del while . Un bucle for o
while puede incluir una cláusula else. En un bucle for, la cláusula else se ejecuta
después de que el bucle alcanza su iteración final. En un bucle while, se ejecuta
después de que la condición del bucle se vuelve falsa. En cualquier tipo de bucle, la
cláusula else no se ejecuta si el bucle fue terminado por una declaración break .
5 is a prime number
6 equals 2 * 3
7 is a prime number
8 equals 2 * 4
9 equals 3 * 3
(Sí, este es el código correcto. Fíjate bien: el else pertenece al ciclo for, no al if.)
Otro lugar donde se puede usar pass es como una marca de lugar para una
función o un cuerpo condicional cuando estás trabajando en código nuevo, lo cual te
permite pensar a un nivel de abstracción mayor. El pass se ignora silenciosamente:
Una sentencia match recibe una expresión y compara su valor con patrones
sucesivos dados en uno o más bloques case. Esto es similar a grandes rasgos con una
sentencia switch en C, Java o JavaScript (y muchos otros lenguajes) pero es más similar
a la comparación de patrones en lenguajes como Rust o Haskell. Sólo se ejecuta el primer
patrón que coincide y también es capaz de extraer componentes (elementos de una
secuencia o atributos de un objeto) de un valor y ponerlos en variables.
La forma más simple compara un valor expuesto con uno o más literales:
def http_error(status):
match status:
case 400:
return "Bad request"
case 404:
return "Not found"
case 418:
return "I'm a teapot"
case _:
return "Something's wrong with the internet"
¡Observa este caso con cuidado! El primer patrón tiene dos literales y puede
considerarse una extensión del patrón literal que se mostró anteriormente. Pero los
siguientes dos patrones combinan un literal y una variable, y la variable liga uno de los
elementos del sujeto (point). El cuarto patrón captura ambos elementos, lo que lo hace
conceptualmente similar a la asignación que desempaqueta (x, y) = point.
Si estás usando clases para estructurar tus datos, puedes usar el nombre de la
clase seguida de una lista de argumentos similar a la de un constructor, pero con la
capacidad de capturar atributos en variables:
class Point:
def __init__(self, x, y):
self.x = x
self.y = y
def where_is(point):
match point:
case Point(x=0, y=0):
print("Origin")
case Point(x=0, y=y):
print(f"Y={y}")
case Point(x=x, y=0):
print(f"X={x}")
case Point():
print("Somewhere else")
case _:
print("Not a point")
Una recomendación para leer patrones es verlos como una forma extendida de lo
que pondrías en el lado izquierdo de una asignación, para así entender cuáles variables
tomarían qué valores. Sólo los nombres que aparecen por si solos (cómo var arriba) son
asignados por una sentencia match. Nunca se asigna a los nombres con puntos (como
foo.bar), nombres de atributos (los x= e y= arriba) o nombres de clases (reconocidos
por los «(…)» junto a ellos, como Point arriba).
class Point:
__match_args__ = ('x', 'y')
def __init__(self, x, y):
self.x = x
self.y = y
match points:
case []:
print("No points")
case [Point(0, 0)]:
print("The origin")
case [Point(x, y)]:
print(f"Single point {x}, {y}")
case [Point(0, y1), Point(0, y2)]:
print(f"Two on the Y axis at {y1}, {y2}")
case _:
print("Something else")
match point:
case Point(x, y) if x == y:
print(f"Y=X at {x}")
case Point(x, y):
print(f"Not on the diagonal")
• Al igual que las asignaciones con desempaquetado, los patrones de lista o tupla
tienen exactamente el mismo sentido y realmente coinciden con cualquier
secuencia arbitraria. Una excepción importante es que no coinciden ni con
iteradores ni con cadenas de caracteres.
• Los patrones de secuencia soportan desempaquetado extendido: [x, y,
*otros] y (x, y, *otros) funcionan de manera similar a las asignaciones con
desempaquetado. El nombre luego de * también puede ser _, con lo cual (x, y,
*_) coincide con cualquier secuencia de al menos dos elementos, sin ligar ninguno
de los demás elementos.
• Los patrones de mapeo: {"ancho_de_banda": c, "latencia": l} capturan
los valores "ancho_de_banda" y "latencia" de un diccionario. A diferencia de
los patrones de secuencia, las claves adicionales son ignoradas. Puede usarse un
desempaquetado como **otros . (Aunque **_ sería redundante, con lo cual no
está permitido)
• Pueden capturarse subpatrones usando la palabra clave as:
• La mayoría de los literales se comparan por igualdad, pero las instancias únicas
True, False y None se comparan por identidad.
• En un patrón pueden usarse constantes con nombres. Los nombres deben tener
puntos para impedir que sean interpretados como variables a capturar:
match color:
case Color.RED:
print("I see red!")
case Color.GREEN:
print("Grass is green")
Para una explicación más detallada y más ejemplos, puede leerse on line PEP 636
que está escrita en un formato de tutorial.
Podemos crear una función que escriba la serie de Fibonacci hasta un límite
determinado:
La palabra reservada def se usa para definir funciones. Debe seguirle el nombre
de la función y la lista de parámetros formales entre paréntesis. Las sentencias que
forman el cuerpo de la función empiezan en la línea siguiente, y deben estar con sangría.
La ejecución de una función introduce una nueva tabla de símbolos usada para las
variables locales de la función. Más precisamente, todas las asignaciones de variables
en la función almacenan el valor en la tabla de símbolos local; así mismo la referencia a
variables primero mira la tabla de símbolos local, luego en la tabla de símbolos local de
las funciones externas, luego la tabla de símbolos global, y finalmente la tabla de
nombres predefinidos. Así, a variables globales y a variables de funciones que engloban
>>> fib
<function fib at 10042ed0>
>>> f = fib
>>> f(100)
0 1 1 2 3 5 8 13 21 34 55 89
Viniendo de otros lenguajes, puedes objetar que fib no es una función, sino un
procedimiento, porque no retorna un valor. De hecho, técnicamente hablando, los
procedimientos sin return sí retornan un valor, aunque uno bastante aburrido. Este
valor se llama None (es un nombre predefinido). El intérprete por lo general no escribe
el valor None si va a ser el único valor escrito. Puede verlo si realmente lo desea
utilizando print():
>>> fib(0)
>>> print(fib(0))
None
Es simple escribir una función que retorne una lista con los números de la serie
de Fibonacci en lugar de imprimirlos:
• La sentencia return retorna un valor en una función. return sin una expresión
como argumento retorna None. Si se alcanza el final de una función, también se
retorna None.
• La sentencia result.append(a) llama a un método del objeto lista result.
La forma más útil es especificar un valor por omisión para uno o más
argumentos. Esto crea una función que puede ser llamada con menos argumentos que
los que permite. Por ejemplo:
Este ejemplo también introduce la palabra reservada in, la cual prueba si una
secuencia contiene o no un determinado valor.
i = 5
def f(arg=i):
print(arg)
i = 6
f()
imprimirá 5.
Advertencia importante: El valor por omisión es evaluado solo una vez. Existe una
diferencia cuando el valor por omisión es un objeto mutable como una lista, diccionario,
print(f(1))
print(f(2))
print(f(3))
Imprimirá
[1]
[1, 2]
[1, 2, 3]
En una llamada a una función, los argumentos nombrados deben seguir a los
argumentos posicionales. Cada uno de los argumentos nombrados pasados deben
coincidir con un argumento aceptado por la función (por ejemplo, actor no es un
argumento válido para la función parrot), y el orden de los mismos no es importante.
Esto también se aplica a los argumentos obligatorios (por ejemplo,
parrot(voltage=1000) también es válido). Ningún argumento puede recibir más de
un valor al mismo tiempo. Aquí hay un ejemplo que falla debido a esta restricción:
Se debe notar que el orden en el cual los argumentos nombrados son impresos
está garantizado para coincidir con el orden en el cual fueron provistos en la llamada a
la función.
Por defecto, los argumentos pueden enviarse a una función Python o bien por
posición o explícitamente por clave. Para legibilidad y rendimiento tiene sentido
restringir como se pueden enviar los argumentos, así un desarrollador necesitará mirar
solamente la definición de la función para determinar si los argumentos se deben enviar
por posición, por posición o clave, o por clave.
>>> standard_arg(2)
2
>>> standard_arg(arg=2)
2
>>> pos_only_arg(1)
1
>>> pos_only_arg(arg=1)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: pos_only_arg() got some positional-only arguments
passed as keyword arguments: 'arg'
>>> kwd_only_arg(arg=3)
3
>>> combined_example(1, 2, 3)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: combined_example() takes 2 positional arguments but
3 were given
No hay una llamada posible que lo haga retornar True ya que la palabra clave
'name' siempre se vinculará al primer parámetro. Por ejemplo:
4.8.3.5. Resumen
A modo de guía:
• En el caso de una API, use solo posicional para evitar que se rompan los cambios de
la API si el nombre del parámetro se modifica en el futuro.
El ejemplo anterior muestra el uso de una expresión lambda para retornar una
función. Otro uso es para pasar pequeñas funciones como argumentos
>>> pairs = [(1, 'one'), (2, 'two'), (3, 'three'), (4, 'four')]
>>> pairs.sort(key=lambda pair: pair[1])
>>> pairs
[(4, 'four'), (1, 'one'), (3, 'three'), (2, 'two')]
La primera línea debe ser siempre un resumen corto y conciso del propósito del
objeto. Para ser breve, no se debe mencionar explícitamente el nombre o tipo del
objeto, ya que estos están disponibles de otros modos (excepto si el nombre es un verbo
que describe el funcionamiento de la función). Esta línea debe empezar con una letra
mayúscula y terminar con un punto.
Para Python, PEP 8 se erigió como la guía de estilo a la que más proyectos
adhirieron; promueve un estilo de programación fácil de leer y visualmente agradable.
Todos los desarrolladores Python deben leerlo en algún momento; aquí están extraídos
los puntos más importantes:
Notas al pie
1 En realidad, llamadas por referencia de objeto sería una mejor descripción, ya que si
se pasa un objeto mutable, quien realiza la llamada verá cualquier cambio que se realice
sobre el mismo (por ejemplo, ítems insertados en una lista).
Este capítulo describe en más detalle algunas cosas que ya has aprendido y
agrega algunas cosas nuevas también.
El tipo de dato lista tiene algunos métodos más. Aquí están todos los
métodos de los objetos lista:
list.append(x)
list.extend(iterable)
Extiende la lista agregándole todos los ítems del iterable. Equivale a a[len(a):] =
iterable.
list.insert(i, x)
Inserta un ítem en una posición dada. El primer argumento es el índice del ítem delante
del cual se insertará, por lo tanto a.insert(0, x) inserta al principio de la lista y
a.insert(len(a), x) equivale a a.append(x).
list.remove(x)
Quita el primer ítem de la lista cuyo valor sea x. Lanza un ValueError si no existe tal
ítem.
list.pop([i])
list.clear()
Retorna el índice basado en cero del primer elemento cuyo valor sea igual a x. Lanza una
excepción ValueError si no existe tal elemento.
list.count(x)
Ordena los elementos de la lista in situ (los argumentos pueden ser usados para
personalizar el orden de la lista, ver sorted() para su explicación).
list.reverse()
list.copy()
Es posible que haya notado que los métodos como insert, remove o sort que
solo modifican la lista no tienen ningún valor devuelto impreso: devuelven el valor
predeterminado None. 1 Este es un principio de diseño para todas las estructuras de
datos mutables en Python.
Otra cosa que puedes observar es que no todos los datos se pueden ordenar o
comparar. Por ejemplo, [None, 'hello', 10] no se puede ordenar ya que los
enteros no se pueden comparar con strings y None no se puede comparar con los otros
tipos. También hay algunos tipos que no tienen una relación de orden definida. Por
ejemplo, 3+4j < 5+7j no es una comparación válida.
Los métodos de lista hacen que resulte muy fácil usar una lista como una
pila, donde el último elemento añadido es el primer elemento retirado («último en
entrar, primero en salir»). Para agregar un elemento a la cima de la pila, utiliza
append(). Para retirar un elemento de la cima de la pila, utiliza pop() sin un índice
explícito. Por ejemplo:
También es posible usar una lista como una cola, donde el primer elemento
añadido es el primer elemento retirado («primero en entrar, primero en salir»); sin
Las comprensiones de listas ofrecen una manera concisa de crear listas. Sus
usos comunes son para hacer nuevas listas donde cada elemento es el resultado de
algunas operaciones aplicadas a cada miembro de otra secuencia o iterable, o para crear
un segmento de la secuencia de esos elementos para satisfacer una condición
determinada.
Por ejemplo, asumamos que queremos crear una lista de cuadrados, como:
>>> squares = []
>>> for x in range(10):
... squares.append(x**2)
...
>>> squares
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
Nótese que esto crea (o sobreescribe) una variable llamada x que sigue existiendo
luego de que el bucle haya terminado. Podemos calcular la lista de cuadrados sin ningún
efecto secundario haciendo:
y es equivalente a:
>>> combs = []
>>> for x in [1,2,3]:
... for y in [3,1,4]:
... if x != y:
... combs.append((x, y))
...
>>> combs
[(1, 3), (1, 4), (2, 3), (2, 1), (2, 4), (3, 1), (3, 4)]
Considera el siguiente ejemplo de una matriz de 3x4 implementada como una lista
de tres listas de largo 4:
>>> matrix = [
... [1, 2, 3, 4],
... [5, 6, 7, 8],
... [9, 10, 11, 12],
... ]
>>> transposed = []
>>> for i in range(4):
... transposed.append([row[i] for row in matrix])
...
>>> transposed
[[1, 5, 9], [2, 6, 10], [3, 7, 11], [4, 8, 12]]
>>> transposed = []
>>> for i in range(4):
... # the following 3 lines implement the nested listcomp
... transposed_row = []
... for row in matrix:
... transposed_row.append(row[i])
... transposed.append(transposed_row)
...
>>> transposed
[[1, 5, 9], [2, 6, 10], [3, 7, 11], [4, 8, 12]]
>>> list(zip(*matrix))
[(1, 5, 9), (2, 6, 10), (3, 7, 11), (4, 8, 12)]
Puedes ver online Desempaquetando una lista de argumentos para detalles sobre el
asterisco de esta línea.
Hay una manera de quitar un ítem de una lista dado su índice en lugar de su
valor: la instrucción del. Esta es diferente del método pop(), el cual retorna un valor.
La instrucción del también puede usarse para quitar secciones de una lista o vaciar la
>>> del a
Hacer referencia al nombre a de aquí en más es un error (al menos hasta que se
le asigne otro valor). Veremos otros usos para del más adelante.
Una tupla está formada por un número de valores separados por comas, por
ejemplo:
Como puedes ver, en la salida las tuplas siempre se encierran entre paréntesis para
que las tuplas anidadas puedan interpretarse correctamente; pueden ingresarse con o
sin paréntesis, aunque a menudo los paréntesis son necesarios de todas formas (si la
tupla es parte de una expresión más grande). No es posible asignar a los ítems
individuales de una tupla, pero sin embargo sí se puede crear tuplas que contengan
objetos mutables, como las listas.
A pesar de que las tuplas puedan parecerse a las listas, frecuentemente se utilizan
en distintas situaciones y para distintos propósitos. Las tuplas son immutable y
normalmente contienen una secuencia heterogénea de elementos que son accedidos al
desempaquetar (ver más adelante en esta sección) o indizar (o incluso acceder por
atributo en el caso de las namedtuples). Las listas son mutable, y sus elementos son
normalmente homogéneos y se acceden iterando a la lista.
>>> empty = ()
>>> singleton = 'hello', # <-- note trailing comma
>>> len(empty)
0
>>> len(singleton)
1
>>> singleton
('hello',)
5.4. Conjuntos
Las llaves o la función set() pueden usarse para crear conjuntos. Notá que para
crear un conjunto vacío tenés que usar set(), no {}; esto último crea un diccionario
vacío, una estructura de datos que discutiremos en la sección siguiente.
5.5. Diccionarios
Otro tipo de dato útil incluido en Python es el diccionario (ver Tipos mapa —
dict). Los diccionarios se encuentran a veces en otros lenguajes como «memorias
asociativas» o «arreglos asociativos». A diferencia de las secuencias, que se indexan
mediante un rango numérico, los diccionarios se indexan con claves, que pueden ser
cualquier tipo inmutable; las cadenas y números siempre pueden ser claves. Las tuplas
pueden usarse como claves si solamente contienen cadenas, números o tuplas; si una
tupla contiene cualquier objeto mutable directa o indirectamente, no puede usarse
como clave. No podés usar listas como claves, ya que las listas pueden modificarse
usando asignación por índice, asignación por sección, o métodos como append() y
extend().
Las operaciones principales sobre un diccionario son guardar un valor con una
clave y extraer ese valor dada la clave. También es posible borrar un par clave:valor con
del. Si usás una clave que ya está en uso para guardar un valor, el valor que estaba
asociado con esa clave se pierde. Es un error extraer un valor usando una clave
inexistente.
Ejecutando list(d) en un diccionario retornará una lista con todas las claves
usadas en el diccionario, en el orden de inserción (si deseas que esté ordenada
Cuando las claves son cadenas simples, a veces resulta más fácil especificar los
pares usando argumentos por palabra clave:
Cuando se itera sobre una secuencia, se puede obtener el índice de posición junto
a su valor correspondiente usando la función enumerate().
Para iterar sobre dos o más secuencias al mismo tiempo, los valores pueden
emparejarse con la función zip().
Para iterar sobre una secuencia ordenada, se utiliza la función sorted() la cual
retorna una nueva lista ordenada dejando a la original intacta.
A veces uno intenta cambiar una lista mientras la está iterando; sin embargo, a
menudo es más simple y seguro crear una nueva lista:
Los operadores booleanos and y or son los llamados operadores cortocircuito: sus
argumentos se evalúan de izquierda a derecha, y la evaluación se detiene en el
momento en que se determina su resultado. Por ejemplo, si A y C son verdaderas pero
B es falsa, en A and B and C no se evalúa la expresión C. Cuando se usa como un
valor general y no como un booleano, el valor retornado de un operador cortocircuito
es el último argumento evaluado.
Las secuencias pueden compararse con otros objetos del mismo tipo de
secuencia. La comparación usa orden lexicográfico: primero se comparan los dos
primeros ítems, si son diferentes esto ya determina el resultado de la comparación; si
son iguales, se comparan los siguientes dos ítems, y así sucesivamente hasta llegar al
final de alguna de las secuencias. Si dos ítems a comparar son ambos secuencias del
mismo tipo, la comparación lexicográfica es recursiva. Si todos los ítems de dos
secuencias resultan iguales, se considera que las secuencias son iguales. Si una secuencia
es la parte inicial de la otra, la secuencia más corta es la más pequeña. El orden
lexicográfico de las cadenas de caracteres utiliza el punto de código Unicode para
ordenar caracteres individuales. Algunos ejemplos de comparación entre secuencias del
mismo tipo:
Observa que comparar objetos de diferentes tipos con < o > es legal siempre y
cuando los objetos tengan los métodos de comparación apropiados. Por ejemplo, los
tipos de números mezclados son comparados de acuerdo con su valor numérico, o sea
0 es igual a 0.0, etc. Si no es el caso, en lugar de proveer un ordenamiento arbitrario, el
intérprete lanzará una excepción TypeError.
Notas al pie
Para soportar esto, Python tiene una manera de poner definiciones en un archivo
y usarlos en un script o en una instancia del intérprete. Este tipo de ficheros se llama
módulo; las definiciones de un módulo pueden ser importadas a otros módulos o al
módulo principal (la colección de variables a las que tienes acceso en un script ejecutado
en el nivel superior y en el modo calculadora).
>>> fibo.fib(1000)
0 1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987
>>> fibo.fib2(100)
[0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89]
>>> fibo.__name__
'fibo'
Cada módulo tiene su propio espacio de nombres privado, que es utilizado como
espacio de nombres global por todas las funciones definidas en el módulo. De este
modo, el autor de un módulo puede utilizar variables globales en el módulo sin
preocuparse por choques accidentales con las variables globales de un usuario. Por otro
lado, si sabes lo que estás haciendo puedes tocar las variables globales de un módulo
con la misma notación que se utiliza para referirse a sus funciones,
modname.itemname.
Hay incluso una variante para importar todos los nombres que un módulo define:
Esto importa todos los nombres excepto los que inician con un guión bajo (_). La
mayoría de las veces los programadores de Python no usan esto ya que introduce en el
intérprete un conjunto de nombres desconocido, posiblemente escondiendo algunas de
las definiciones previas.
Si el nombre del módulo es seguido por as, el nombre siguiendo as queda ligado
directamente al módulo importado.
Por razones de eficiencia, cada módulo es importado solo una vez por sesión del
intérprete. Por lo tanto, si cambias tus módulos, debes reiniciar el interprete – ó, si es
un solo módulo que quieres probar de forma interactiva, usa importlib.reload(),
por ejemplo: import importlib; importlib.reload(modulename).
el código en el módulo será ejecutado, tal como si lo hubieses importado, pero con
__name__ con el valor de "__main__". Eso significa que agregando este código al final
de tu módulo:
if __name__ == "__main__":
import sys
fib(int(sys.argv[1]))
puedes hacer que el archivo sea utilizable tanto como script, como módulo importable,
porque el código que analiza la línea de órdenes sólo se ejecuta si el módulo es
ejecutado como archivo principal:
$ python fibo.py 50
0 1 1 2 3 5 8 13 21 34
Nota
En los sistemas de archivo que soportan enlaces simbólicos, el directorio que contiene
el script de entrada es calculado luego de seguir el enlace simbólico. En otras palabras,
el directorio que contiene el enlace simbólico no es agregado al camino de búsqueda
del módulo.
La función integrada dir() se usa para encontrar qué nombres define un módulo.
Retorna una lista ordenada de cadenas:
Sin argumentos, dir() lista los nombres que tienes actualmente definidos:
>>> a = [1, 2, 3, 4, 5]
>>> import fibo
>>> fib = fibo.fib
>>> dir()
['__builtins__', '__name__', 'a', 'fib', 'fibo', 'sys']
Nótese que lista todos los tipos de nombres: variables, módulos, funciones, etc.
dir() no lista los nombres de las funciones y variables integradas. Si quieres una
lista de esos, están definidos en el módulo estándar builtins:
6.4. Paquetes
Supongamos que quieres designar una colección de módulos (un «paquete») para
el manejo uniforme de archivos y datos de sonidos. Hay diferentes formatos de archivos
de sonido (normalmente reconocidos por su extensión, por ejemplo: .wav, .aiff,
.au), por lo que tienes que crear y mantener una colección siempre creciente de
módulos para la conversión entre los distintos formatos de archivos. Hay muchas
operaciones diferentes que quizás quieras ejecutar en los datos de sonido (como
mezclarlos, añadir eco, aplicar una función ecualizadora, crear un efecto estéreo
artificial), por lo que además estarás escribiendo una lista sin fin de módulos para
realizar estas operaciones. Aquí hay una posible estructura para tu paquete (expresados
en términos de un sistema jerárquico de archivos):
El archivo __init__.py son necesarios para que Python trate los directorios que
contienen el archivo como paquetes. Esto evita que los directorios con un nombre
común, como cadena, oculten involuntariamente los módulos válidos que aparecen más
adelante en la ruta de búsqueda del módulo. En el caso más simple, __init__.py
puede ser simplemente un archivo vacío, pero también puede ejecutar código de
inicialización para el paquete o establecer la variable __all__, que se describe más
adelante.
Los usuarios del paquete pueden importar módulos individuales del mismo, por
ejemplo:
import sound.effects.echo
Esto también carga el submódulo echo, y lo deja disponible sin su prefijo de paquete,
por lo que puede usarse así:
De nuevo, esto carga el submódulo echo, pero deja directamente disponible a la función
echofilter():
Nótese que al usar from package import item, el ítem puede ser tanto un
submódulo (o subpaquete) del paquete, o algún otro nombre definido en el paquete,
como una función, clase, o variable. La declaración import primero verifica si el ítem
está definido en el paquete; si no, asume que es un módulo y trata de cargarlo. Si no lo
puede encontrar, se genera una excepción ImportError.
Idealmente, uno esperaría que esto de alguna manera vaya al sistema de archivos,
encuentre cuales submódulos están presentes en el paquete, y los importe a todos. Esto
puede tardar mucho y el importar sub-módulos puede tener efectos secundarios no
deseados que sólo deberían ocurrir cuando se importe explícitamente el sub-módulo.
La única solución es que el autor del paquete provea un índice explícito del
paquete. La declaración import usa la siguiente convención: si el código del
__init__.py de un paquete define una lista llamada __all__, se toma como la lista
de los nombres de módulos que deberían ser importados cuando se hace from
package import *. Es tarea del autor del paquete mantener actualizada esta lista
cuando se libera una nueva versión del paquete. Los autores de paquetes podrían
decidir no soportarlo, si no ven un uso para importar * en sus paquetes. Por ejemplo, el
archivo sound/effects/__init__.py podría contener el siguiente código:
Tenga en cuenta que los submódulos pueden quedar ensombrecidos por nombres
definidos localmente. Por ejemplo, si ha añadido una función reverse al archivo
sound/effects/__init__.py, la importación
__all__ = [
"echo", # refers to the 'echo.py' file
"surround", # refers to the 'surround.py' file
"reverse", # !!! refers to the 'reverse' function now !!!
]
import sound.effects.echo
import sound.effects.surround
from sound.effects import *
A pesar de que ciertos módulos están diseñados para exportar solo nombres que
siguen ciertos patrones cuando uses import *, también se considera una mala práctica
en código de producción.
Nótese que los imports relativos se basan en el nombre del módulo actual. Ya que
el nombre del módulo principal es siempre "__main__", los módulos pensados para
usarse como módulo principal de una aplicación Python siempre deberían usar import
absolutos.
Notas al pie
• Para usar literales de cadena formateados, comience una cadena con f o F antes
de la comilla de apertura o comillas triples. Dentro de esta cadena, se puede escribir
una expresión de Python entre los caracteres { y } que pueden hacer referencia a
variables o valores literales.
• Por último, puede realizar todo el control de cadenas usted mismo mediante
operaciones de concatenación y segmentación de cadenas para crear cualquier
diseño que se pueda imaginar. El tipo de cadena tiene algunos métodos que realizan
operaciones útiles para rellenar cadenas a un ancho de columna determinado.
Algunos ejemplos:
El módulo string contiene una clase Template que ofrece otra forma de
sustituir valores en cadenas, utilizando marcadores de posición como $x y
reemplazarlos con valores desde un diccionario, pero esto ofrece mucho menos control
en el formato.
Pasar un entero después de ':' hará que ese campo sea un número mínimo de
caracteres de ancho. Esto es útil para hacer que las columnas se alineen.
>>>
Las llaves y caracteres dentro de las mismas (llamados campos de formato) son
reemplazadas con los objetos pasados en el método str.format(). Un número en las
llaves se refiere a la posición del objeto pasado en el método str.format().
Si tiene una cadena de caracteres de formato realmente larga que no desea dividir,
sería bueno si pudiera hacer referencia a las variables que se formatearán por nombre
en lugar de por posición. Esto se puede hacer simplemente pasando el diccionario y
usando corchetes '[]' para acceder a las claves.
Para una completa descripción del formateo de cadenas con str.format(), ver
Formato de cadena de caracteres personalizado.
(Nótese que el espacio existente entre cada columna es añadido debido a como
funciona print(): siempre añade espacios entre sus argumentos.)
>>> '12'.zfill(5)
'00012'
>>> '-3.14'.zfill(7)
'-003.14'
>>> '3.14159265359'.zfill(5)
'3.14159265359'
La función open() retorna un file object, y se usa normalmente con dos argumentos
posicionales y un argumento nombrado:
Cuando se lee en modo texto, por defecto se convierten los fin de lineas que son
específicos a las plataformas (\n en Unix, \r\n en Windows) a solamente \n. Cuando
>>> # We can check that the file has been automatically closed.
>>> f.closed
True
Advertencia
Llamar a f.write() sin usar la palabra clave with o sin llamar a f.close() podría
dar como resultado que los argumentos de f.write() no se escriban completamente
en disco, incluso si el programa se termina correctamente.
>>> f.close()
>>> f.read()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: I/O operation on closed file.
Para leer el contenido de una archivo utiliza f.read(size), el cual lee alguna
cantidad de datos y los retorna como una cadena (en modo texto) o un objeto de bytes
(en modo binario). size es un argumento numérico opcional. Cuando se omite size o es
negativo, el contenido entero del archivo será leído y retornado; es tu problema si el
archivo es el doble de grande que la memoria de tu máquina. De otra manera, son leídos
y retornados como máximo size caracteres (en modo texto) o size bytes (en modo
binario). Si se alcanzó el fin del archivo, f.read() retornará una cadena vacía ('').
>>> f.read()
'This is the entire file.\n'
>>> f.read()
''
f.readline() lee una sola linea del archivo; el carácter de fin de linea (\n) se
deja al final de la cadena, y sólo se omite en la última linea del archivo si el mismo no
termina en un fin de linea. Esto hace que el valor de retorno no sea ambiguo; si
f.readline() retorna una cadena vacía, es que se alcanzó el fin del archivo, mientras
que una linea en blanco es representada por '\n', una cadena conteniendo sólo un
único fin de linea.
>>> f.readline()
'This is the first line of the file.\n'
>>> f.readline()
'Second line of the file\n'
>>> f.readline()
''
Para leer líneas de un archivo, puedes iterar sobre el objeto archivo. Esto es
eficiente en memoria, rápido, y conduce a un código más simple:
Otros tipos de objetos necesitan ser convertidos – tanto a una cadena (en modo
texto) o a un objeto de bytes (en modo binario) – antes de escribirlos:
Nota
Si tienes un objeto x, puedes ver su representación JSON con una simple línea de
código:
json.dump(x, f)
Para decodificar un objeto nuevamente, si f es un objeto binary file o text file que
fue abierto para lectura:
x = json.load(f)
Nota
Ver También
Hasta ahora los mensajes de error apenas habían sido mencionados, pero si
has probado los ejemplos anteriores probablemente hayas visto algunos. Hay (al menos)
dos tipos diferentes de errores: errores de sintaxis y excepciones.
8.2. Excepciones
>>> 10 * (1/0)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ZeroDivisionError: division by zero
>>> 4 + spam*3
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'spam' is not defined
>>> '2' + 2
Traceback (most recent call last):
• Primero, se ejecuta la cláusula try (la(s) linea(s) entre las palabras reservadas try
y la except).
• Si no ocurre ninguna excepción, la cláusula except se omite y la ejecución de la
cláusula try finaliza.
• Si ocurre una excepción durante la ejecución de la cláusula try, se omite el resto
de la cláusula. Luego, si su tipo coincide con la excepción nombrada después de
la palabra clave except, se ejecuta la cláusula except, y luego la ejecución
continúa después del bloque try/except.
• Si ocurre una excepción que no coincide con la indicada en la cláusula except se
pasa a los try más externos; si no se encuentra un gestor, se genera una
unhandled exception (excepción no gestionada) y la ejecución se interrumpe con
un mensaje como el que se muestra arriba.
Una declaración try puede tener más de una cláusula except, para especificar
gestores para diferentes excepciones. Como máximo, se ejecutará un gestor. Los
gestores solo manejan las excepciones que ocurren en la cláusula try correspondiente,
no en otros gestores de la misma declaración try. Una cláusula except puede nombrar
múltiples excepciones como una tupla entre paréntesis, por ejemplo:
class B(Exception):
pass
class C(B):
pass
class D(C):
pass
Nótese que si las cláusulas except estuvieran invertidas (con except B primero),
habría impreso B, B, B — se usa la primera cláusula except coincidente.
Cuando ocurre una excepción, puede tener un valor asociado, también conocido
como el argumento de la excepción. La presencia y el tipo de argumento depende del
tipo de excepción.
>>> try:
... raise Exception('spam', 'eggs')
... except Exception as inst:
... print(type(inst)) # the exception type
... print(inst.args) # arguments stored in .args
... print(inst) # __str__ allows args to be printed
directly,
... # but may be overridden in exception
subclasses
... x, y = inst.args # unpack args
... print('x =', x)
... print('y =', y)
...
<class 'Exception'>
('spam', 'eggs')
('spam', 'eggs')
x = spam
y = eggs
Exception se puede utilizar como un comodín que atrapa (casi) todo. Sin
embargo, es una buena práctica ser lo más específico posible con los tipos de
excepciones que pretendemos manejar, y permitir que cualquier excepción inesperada
se propague.
import sys
try:
f = open('myfile.txt')
s = f.readline()
i = int(s.strip())
except OSError as err:
print("OS error:", err)
except ValueError:
print("Could not convert data to an integer.")
except Exception as err:
print(f"Unexpected {err=}, {type(err)=}")
raise
La declaración try … except tiene una cláusula else opcional, que, cuando está
presente, debe seguir todas las cláusulas except. Es útil para el código que debe
ejecutarse si la cláusula try no lanza una excepción. Por ejemplo:
El único argumento de raise indica la excepción a lanzar. Debe ser una instancia
de excepción o una clase de excepción (una clase que derive de BaseException, como
Exception o una de sus subclases). Si se pasa una clase de excepción, se instanciará
implícitamente llamando a su constructor sin argumentos:
>>> try:
... raise NameError('HiThere')
... except NameError:
... print('An exception flew by!')
>>> try:
... open("database.sqlite")
... except OSError:
... raise RuntimeError("unable to handle error")
...
Traceback (most recent call last):
File "<stdin>", line 2, in <module>
FileNotFoundError: [Errno 2] No such file or directory:
'database.sqlite'
Esto puede resultar útil cuando está transformando excepciones. Por ejemplo:
>>> try:
... open('database.sqlite')
... except OSError:
... raise RuntimeError from None
...
Traceback (most recent call last):
File "<stdin>", line 4, in <module>
RuntimeError
Los programas pueden nombrar sus propias excepciones creando una nueva
clase excepción (mira Clases para más información sobre las clases de Python). Las
excepciones, típicamente, deberán derivar de la clase Exception, directa o
indirectamente.
Las clases de Excepción pueden ser definidas de la misma forma que cualquier otra
clase, pero es habitual mantenerlas lo más simples posible, a menudo ofreciendo solo
un número de atributos con información sobre el error que leerán los gestores de la
excepción.
Muchos módulos estándar definen sus propias excepciones para reportar errores
que pueden ocurrir en funciones propias.
>>> try:
... raise KeyboardInterrupt
... finally:
... print('Goodbye, world!')
...
Goodbye, world!
KeyboardInterrupt
Traceback (most recent call last):
File "<stdin>", line 2, in <module>
El problema con este código es que deja el archivo abierto por un periodo de
tiempo indeterminado luego de que esta parte termine de ejecutarse. Esto no es un
problema en scripts simples, pero puede ser un problema en aplicaciones más grandes.
La declaración with permite que los objetos como archivos sean usados de una forma
que asegure que siempre se los libera rápido y en forma correcta.:
with open("myfile.txt") as f:
for line in f:
print(line, end="")
>>> excs = []
... for test in tests:
... try:
... test.run()
... except Exception as e:
... excs.append(e)
...
>>> if excs:
... raise ExceptionGroup("Test Failures", excs)
...
(Sin haber una terminología universalmente aceptada sobre clases, haré uso
ocasional de términos de Smalltalk y C++. Usaría términos de Modula-3, ya que su
semántica orientada a objetos es más cercana a Python que C++, pero no espero que
muchos lectores hayan escuchado hablar de él.)
Antes de ver clases, primero debo decirte algo acerca de las reglas de ámbito de
Python. Las definiciones de clases hacen unos lindos trucos con los espacios de nombres,
y necesitas saber cómo funcionan los alcances y espacios de nombres para entender por
completo cómo es la cosa. De paso, los conocimientos en este tema son útiles para
cualquier programador Python avanzado.
Por cierto, yo uso la palabra atributo para cualquier cosa después de un punto; por
ejemplo, en la expresión z.real, real es un atributo del objeto z. Estrictamente
hablando, las referencias a nombres en módulos son referencias a atributos: en la
expresión modulo.funcion, modulo es un objeto módulo y funcion es un atributo
de éste. En este caso hay una relación directa entre los atributos del módulo y los
nombres globales definidos en el módulo: ¡están compartiendo el mismo espacio de
nombres! 1
La declaración global puede usarse para indicar que ciertas variables viven en el
ámbito global y deberían reasignarse allí; la declaración nonlocal indica que ciertas
variables viven en un ámbito encerrado y deberían reasignarse allí.
def scope_test():
def do_local():
spam = "local spam"
def do_nonlocal():
nonlocal spam
spam = "nonlocal spam"
def do_global():
global spam
spam = "global spam"
scope_test()
print("In global scope:", spam)
También puedes ver que no había vinculación para spam antes de la asignación global.
Las clases introducen un poquito de sintaxis nueva, tres nuevos tipos de objetos y
algo de semántica nueva.
class ClassName:
<statement-1>
.
.
.
<statement-N>
class MyClass:
"""A simple example class"""
i = 12345
def f(self):
return 'hello world'
x = MyClass()
crea una nueva instancia de la clase y asigna este objeto a la variable local x.
def __init__(self):
self.data = []
x = MyClass()
Ahora, ¿Qué podemos hacer con los objetos instancia? La única operación
que es entendida por los objetos instancia es la referencia de atributos. Hay dos tipos
de nombres de atributos válidos, atributos de datos y métodos.
x.counter = 1
while x.counter < 10:
x.counter = x.counter * 2
print(x.counter)
del x.counter
x.f()
De hecho, tal vez hayas adivinado la respuesta: lo que tienen de especial los
métodos es que el objeto es pasado como el primer argumento de la función. En nuestro
ejemplo, la llamada x.f() es exactamente equivalente a MyClass.f(x). En general,
llamar a un método con una lista de n argumentos es equivalente a llamar a la función
correspondiente con una lista de argumentos que es creada insertando el objeto del
método antes del primer argumento.
En general, las variables de instancia son para datos únicos de cada instancia y las
variables de clase son para atributos y métodos compartidos por todas las instancias de
la clase:
class Dog:
>>> d = Dog('Fido')
>>> e = Dog('Buddy')
>>> d.kind # shared by all dogs
'canine'
>>> e.kind # shared by all dogs
'canine'
>>> d.name # unique to d
'Fido'
>>> e.name # unique to e
'Buddy'
Como se vio en Unas palabras sobre nombres y objetos, los datos compartidos
pueden tener efectos inesperados que involucren objetos mutable como ser listas y
diccionarios. Por ejemplo, la lista tricks en el siguiente código no debería ser usada como
variable de clase porque una sola lista sería compartida por todos las instancias de Dog:
class Dog:
>>> d = Dog('Fido')
>>> e = Dog('Buddy')
>>> d.add_trick('roll over')
>>> e.add_trick('play dead')
>>> d.tricks # unexpectedly shared by all dogs
['roll over', 'play dead']
class Dog:
>>> d = Dog('Fido')
>>> e = Dog('Buddy')
>>> d.add_trick('roll over')
>>> e.add_trick('play dead')
>>> d.tricks
['roll over']
>>> e.tricks
['play dead']
A los atributos de datos los pueden hacer referencia tanto los métodos como los
usuarios («clientes») ordinarios de un objeto. En otras palabras, las clases no se usan
para implementar tipos de datos abstractos puros. De hecho, en Python no hay nada
que haga cumplir el ocultar datos; todo se basa en convención. (Por otro lado, la
implementación de Python, escrita en C, puede ocultar por completo detalles de
implementación y el control de acceso a un objeto si es necesario; esto se puede usar
en extensiones a Python escritas en C.)
Los clientes deben usar los atributos de datos con cuidado; éstos pueden romper
invariantes que mantienen los métodos si pisan los atributos de datos. Observa que los
clientes pueden añadir sus propios atributos de datos a una instancia sin afectar la
No hay un atajo para hacer referencia a atributos de datos (¡u otros métodos!)
desde dentro de un método. A mi parecer, esto en realidad aumenta la legibilidad de los
métodos: no existe posibilidad alguna de confundir variables locales con variables de
instancia cuando repasamos un método.
class C:
f = f1
def g(self):
return 'hello world'
h = g
class Bag:
def __init__(self):
self.data = []
Todo valor es un objeto, y por lo tanto tiene una clase (también llamado su tipo).
Ésta se almacena como objeto.__class__.
9.5. Herencia
Por supuesto, una característica del lenguaje no sería digna del nombre
«clase» si no soportara herencia. La sintaxis para una definición de clase derivada se ve
así:
class DerivedClassName(BaseClassName):
<statement-1>
.
.
.
<statement-N>
class DerivedClassName(modname.BaseClassName):
Las clases derivadas pueden redefinir métodos de su clase base. Como los
métodos no tienen privilegios especiales cuando llaman a otros métodos del mismo
objeto, un método de la clase base que llame a otro método definido en la misma clase
base puede terminar llamando a un método de la clase derivada que lo haya redefinido.
(Para los programadores de C++: en Python todos los métodos son en efecto
virtuales.)
<statement-1>
Para la mayoría de los propósitos, en los casos más simples, podés pensar en la
búsqueda de los atributos heredados de clases padres como primero en profundidad,
de izquierda a derecha, sin repetir la misma clase cuando está dos veces en la jerarquía.
Por lo tanto, si un atributo no se encuentra en DerivedClassName, se busca en
Base1, luego (recursivamente) en las clases base de Base1, y sólo si no se encuentra
allí se lo busca en Base2, y así sucesivamente.
La modificación de nombres es útil para dejar que las subclases sobreescriban los
métodos sin romper las llamadas a los métodos desde la misma clase. Por ejemplo:
class Mapping:
def __init__(self, iterable):
self.items_list = []
self.__update(iterable)
class MappingSubclass(Mapping):
Hay que aclarar que las reglas de modificación de nombres están diseñadas
principalmente para evitar accidentes; es posible acceder o modificar una variable que
es considerada como privada. Esto hasta puede resultar útil en circunstancias especiales,
tales como en el depurador.
9.7. Cambalache
@dataclass
class Employee:
name: str
dept: str
salary: int
>>>
Algún código Python que espera un tipo abstracto de datos en particular puede
frecuentemente recibir en cambio una clase que emula los métodos de aquel tipo de
datos. Por ejemplo, si tenés una función que formatea algunos datos a partir de un
objeto archivo, podés definir una clase con métodos read() y readline() que
obtengan los datos de alguna cadena en memoria intermedia, y pasarlo como
argumento.
9.8. Iteradores
Es probable que hayas notado que la mayoría de los objetos contenedores pueden
ser recorridos usando una sentencia for:
>>> s = 'abc'
>>> it = iter(s)
>>> it
<str_iterator object at 0x10c90e650>
>>> next(it)
'a'
>>> next(it)
'b'
>>> next(it)
'c'
>>> next(it)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
next(it)
StopIteration
class Reverse:
"""Iterator for looping over a sequence backwards."""
def __init__(self, data):
def __iter__(self):
return self
def __next__(self):
if self.index == 0:
raise StopIteration
self.index = self.index - 1
return self.data[self.index]
>>>
9.9. Generadores
Generators son una herramienta simple y poderosa para crear iteradores. Están
escritas como funciones regulares pero usan la palabra clave yield siempre que
quieran retornar datos. Cada vez que se llama a next(), el generador se reanuda donde
lo dejó (recuerda todos los valores de datos y qué instrucción se ejecutó por última vez).
Un ejemplo muestra que los generadores pueden ser trivialmente fáciles de crear:
def reverse(data):
for index in range(len(data)-1, -1, -1):
yield data[index]
>>>
Otra característica clave es que las variables locales y el estado de la ejecución son
guardados automáticamente entre llamadas. Esto hace que la función sea más fácil de
escribir y quede mucho más claro que hacerlo usando variables de instancia tales como
self.indice y self.datos.
Algunos generadores simples pueden ser escritos de manera concisa como expresiones
usando una sintaxis similar a las comprensiones de listas, pero con paréntesis en lugar
de corchetes. Estas expresiones están hechas para situaciones donde el generador es
utilizado de inmediato por la función que lo encierra. Las expresiones generadoras son
más compactas, pero menos versátiles que las definiciones completas de generadores y
tienden a ser más amigables con la memoria que sus comprensiones de listas
equivalentes.
Ejemplos:
Notas al pie
1 Excepto por una cosa. Los objetos módulo tienen un atributo de sólo lectura secreto
llamado __dict__ que retorna el diccionario usado para implementar el espacio de
nombres del módulo; el nombre __dict__ es un atributo pero no un nombre global.
Obviamente, usar esto viola la abstracción de la implementación del espacio de
nombres, y debería ser restringido a cosas como depuradores post-mortem.
>>> import os
>>> os.getcwd() # Return the current working directory
'C:\\Python311'
>>> os.chdir('/server/accesslogs') # Change current working
directory
>>> os.system('mkdir today') # Run the command mkdir in the
system shell
0
Las funciones integradas dir() y help() son útiles como ayudas interactivas
para trabajar con módulos grandes como os:
>>> import os
>>> dir(os)
<returns a list of all module functions>
>>> help(os)
<returns an extensive manual page created from the module's
docstrings>
El módulo glob provee una función para hacer listas de archivos a partir de
búsquedas con comodines en directorios:
import argparse
parser = argparse.ArgumentParser(
prog='top',
description='Show top lines from each file')
parser.add_argument('filenames', nargs='+')
parser.add_argument('-l', '--lines', type=int, default=10)
args = parser.parse_args()
print(args)
El módulo sys también tiene atributos para stdin, stdout, y stderr. Este
último es útil para emitir mensajes de alerta y error para que se vean incluso cuando se
haya redirigido stdout:
>>> import re
>>> re.findall(r'\bf[a-z]*', 'which foot or hand fell fastest')
['foot', 'fell', 'fastest']
>>> re.sub(r'(\b[a-z]+) \1', r'\1', 'cat in the the hat')
'cat in the hat'
Cuando se necesita algo más sencillo solamente, se prefieren los métodos de las cadenas
porque son más fáciles de leer y depurar:
10.6. Matemática
Hay varios módulos para acceder a Internet y procesar sus protocolos. Dos de los
más simples son urllib.request para traer data de URLs y smtplib para mandar
correos:
>>>
En contraste con el fino nivel de medición del módulo timeit, los módulos
profile y pstats proveen herramientas para identificar secciones críticas de tiempo
en bloques de código más grandes.
Una forma para desarrollar software de alta calidad es escribir pruebas para
cada función mientras se la desarrolla, y correr esas pruebas frecuentemente durante el
proceso de desarrollo.
El módulo doctest provee una herramienta para revisar un módulo y validar las
pruebas integradas en las cadenas de documentación (o docstring) del programa. La
construcción de las pruebas es tan sencilla como cortar y pegar una ejecución típica
junto con sus resultados en los docstrings. Esto mejora la documentación al proveer al
usuario un ejemplo y permite que el módulo doctest se asegure que el código
permanece fiel a la documentación:
def average(values):
"""Computes the arithmetic mean of a list of numbers.
import doctest
doctest.testmod() # automatically validate the embedded tests
import unittest
class TestStatisticalFunctions(unittest.TestCase):
def test_average(self):
self.assertEqual(average([20, 30, 70]), 40.0)
self.assertEqual(round(average([1, 5, 7]), 1), 4.3)
with self.assertRaises(ZeroDivisionError):
average([])
with self.assertRaises(TypeError):
average(20, 30, 70)
Python tiene una filosofía de «pilas incluidas». Esto se ve mejor en las capacidades
robustas y sofisticadas de sus paquetes más grandes. Por ejemplo:
• El paquete json proporciona un sólido soporte para analizar este popular formato
de intercambio de datos. El módulo csv admite la lectura y escritura directa de
archivos en formato de valor separado por comas, comúnmente compatible con
bases de datos y hojas de cálculo. El procesamiento XML es compatible con los
Este segundo paseo cubre módulos más avanzados que facilitan necesidades
de programación complejas. Estos módulos raramente se usan en scripts cortos.
11.2. Plantillas
El módulo string incluye una clase versátil Template (plantilla) con una
sintaxis simplificada apta para ser editada por usuarios finales. Esto permite que los
usuarios personalicen sus aplicaciones sin necesidad de modificar la aplicación en sí.
>>> t = BatchRename(fmt)
>>> date = time.strftime('%d%b%y')
>>> for i, filename in enumerate(photofiles):
... base, ext = os.path.splitext(filename)
... newname = t.substitute(d=date, n=i, f=ext)
... print('{0} --> {1}'.format(filename, newname))
Las plantillas también pueden ser usadas para separar la lógica del programa de
los detalles de múltiples formatos de salida. Esto permite sustituir plantillas específicas
para archivos XML, reportes en texto plano, y reportes web en HTML.
import struct
start = 0
for i in range(3): # show the first 3 file
headers
start += 14
fields = struct.unpack('<IIIHH', data[start:start+16])
crc32, comp_size, uncomp_size, filenamesize, extra_size =
fields
start += 16
filename = data[start:start+filenamesize]
start += filenamesize
extra = data[start:start+extra_size]
print(filename, hex(crc32), comp_size, uncomp_size)
11.4. Multi-hilos
def run(self):
f = zipfile.ZipFile(self.outfile, 'w',
zipfile.ZIP_DEFLATED)
f.write(self.infile)
f.close()
print('Finished background zip of:', self.infile)
11.5. Registrando
import logging
logging.debug('Debugging information')
logging.info('Informational message')
logging.warning('Warning:config file %s not found',
'server.conf')
Este enfoque funciona bien para la mayoría de las aplicaciones, pero de vez en
cuando existe la necesidad de controlar objetos sólo mientras estén siendo utilizados
por otra cosa. Desafortunadamente, el sólo hecho de controlarlos crea una referencia
que los convierte en permanentes. El módulo weakref provee herramientas para
controlar objetos sin crear una referencia. Cuando el objeto no se necesita más, es
removido automáticamente de una tabla de referencias débiles y se dispara una callback
para objetos weakref. Comúnmente las aplicaciones incluyen cacheo de objetos que son
costosos de crear:
El módulo array provee un objeto array() (vector) que es como una lista que
almacena sólo datos homogéneos y de una manera más compacta. Los ejemplos a
continuación muestran un vector de números guardados como dos números binarios
sin signo de dos bytes (código de tipo "H") en lugar de los 16 bytes por elemento
habituales en listas de objetos int de Python:
El módulo collections provee un objeto deque() que es como una lista más
rápida para agregar y quitar elementos por el lado izquierdo pero con búsquedas más
lentas por el medio. Estos objetos son adecuados para implementar colas y árboles de
búsqueda a lo ancho:
El módulo decimal provee aritmética con tanta precisión como haga falta:
>>> getcontext().prec = 36
>>> Decimal(1) / Decimal(7)
Decimal('0.142857142857142857142857142857142857')
Esto significa que tal vez no sea posible para una instalación de Python cumplir los
requerimientos de todas las aplicaciones. Si la aplicación A necesita la versión 1.0 de un
módulo particular y la aplicación B necesita la versión 2.0, entonces los requerimientos
entran en conflicto e instalar la versión 1.0 o 2.0 dejará una de las aplicaciones sin
funcionar.
Para crear un entorno virtual, decide en que carpeta quieres crearlo y ejecuta el
módulo venv como script con la ruta a la carpeta:
En Windows, ejecuta:
tutorial-env\Scripts\activate.bat
source tutorial-env/bin/activate
(Este script está escrito para la consola bash. Si usas las consolas csh or fish, hay scripts
alternativos activate.csh y activate.fish que deberá usar en su lugar.)
$ source ~/envs/tutorial-env/bin/activate
(tutorial-env) $ python
Python 3.5.1 (default, May 6 2016, 10:59:36)
...
>>> import sys
>>> sys.path
['', '/usr/local/lib/python35.zip', ...,
'~/envs/tutorial-env/lib/python3.5/site-packages']
>>>
:deactivate
pip -m pip uninstall seguido de uno o varios nombres de paquetes eliminará los
paquetes del entorno virtual.
python -m pip list mostrará todos los paquetes instalados en el entorno virtual:
python -m pip freeze retorna una lista de paquetes instalados, pero el formato
de salida es el requerido por python -m pip install. Una convención común es
poner esta lista en un archivo requirements.txt:
pip tiene muchas más opciones. Consulta la guía Instalando módulos de Python
para obtener documentación completa de pip. Cuando haya escrito un paquete y desee
que esté disponible en el índice de paquetes de Python, consulte la guía Distribuir
módulos de Python.
Leer este tutorial probablemente reforzó tu interés por usar Python, deberías
estar ansioso por aplicar Python a la resolución de tus problemas reales. ¿A dónde
deberías ir para aprender más?
Este tutorial forma parte del conjunto de documentación de Python. Algunos otros
documentos que encontrarás en este conjunto son:
Deberías navegar a través de este manual, que da una completa (aunque breve)
referencia sobre los tipos, funciones y módulos en la librería estándar. La distribución
estándar de Python incluye mucho más código adicional. Hay módulos para leer
buzones Unix, recuperar documentos vía HTTP, generar números aleatorios, analizar
opciones de línea de comandos, escribir programas CGI, comprimir datos y muchas
más tareas. Echar una ojeada a la Librería de Referencia te dará una idea de lo que
está disponible.
Explica como instalar módulos adicionales escritos por otros usuarios de Python.
Notas al pie
Esperamos que hayas encontrado este material accesible, enriquecedor y útil, sin
importar en qué punto te encuentres en tu viaje de programación. Con su versatilidad,
simplicidad y gran cantidad de aplicaciones, Python es verdaderamente un lenguaje para todos,
y confiamos en que este recurso te ha proporcionado las herramientas necesarias para
aprovecharlo al máximo.
Recuerda que la programación, al igual que cualquier otra habilidad, mejora con la
práctica. No te desesperes si no entiendes un concepto de inmediato. Tómate tu tiempo, vuelve
a los temas que te resulten más desafiantes y no dudes en buscar ayuda cuando la necesites.
¡Feliz programación!
Tutorial Oficial
de Python 3.1x
Extraído de: https://docs.python.org/es/3/
Python destaca por su legibilidad, simplicidad y versatilidad. Esto lo
convierte en un excelente lenguaje tanto para los que apenas comienzan en el
mundo de la programación como para los programadores experimentados que
buscan mayor eficiencia y flexibilidad. Desde el desarrollo web y análisis de datos
hasta la inteligencia artificial, Python se utiliza en una multitud de campos.
Desde el Centro de Estudios en Modelos de Inteligencia Artificial Aplicados
a las Ciencias Económicas (CeMIACE), hemos trabajado con dedicación para hacer
de este material una guía completa, clara y fácil de seguir. Desde los fundamentos
hasta los detalles más intrincados, estamos seguros de que aquí encontrarás lo
que necesitas para tener éxito en tu camino con Python.
Hemos compilado y mejorado la documentación oficial de la versión 3.1x de
Python, para que puedas disfrutarla de una manera más amena, cercana a la
experiencia de leer un libro.