Autores: Florent Hivert < florent . hivert @ univ-rouen . fr >, Franco Saliola < saliola @ gmail . com >, et al.
Este tutorial es una introducción a la programación básica en Python y Sage, dirigido a lectores con conocimientos elementales de programación pero no familiarizados con el lenguaje de Python. No es un tutorial completo. Un tutorial más completo es el Tutorial de Python. La documentación de Python, y en particular la librería estándar, pueden ser también de utilidad.
This tutorial is an introduction to basic programming in Python and Sage, for readers with elementary notions of programming but not familiar with the Python language. It is far from exhaustive. For a more complete tutorial, have a look at the Python Tutorial. Also Python’s documentation and in particular the standard library can be useful.
Un tutorial más avanzado presenta las nociones de objetos y clases en Python.
Los siguientes son otros recursos para aprender Python:
En Python, la asignación de tipos es dinámica; no hay declaración de variables como tal. La funcion type()
devuelve el tipo de un objeto obj
. Para convertir un objeto a un tipo typ
escriba typ(obj)
asi como en int("123")
. El comando isinstance(ex, typ)
devuelve True
si la expresión ex
es del tipo typ
y False
de lo contrario. Más específicamente, todo valor es una instancia de una clase , y no hay diferencias entre clases y tipos.
El símbolo =
denota la asignación de valores a variables; no se debe confundir con ,==
que denota igualdad matemática. La desigualdad se denota !=
.
Los tipos estándar son bool
, int
, list
, `tuple
<https://docs.python.org/library/functions.html#tuple>$_, $$set$$, $$dict$$, $$str$$.
El tipo bool
( booleano ) tiene dos valores: True
y False
. Las operaciones booleanas se denotan por sus nombres or y``not
.
Los tipos int
y long
de Python son usados para representar números enteros de tamaño limitado. Para manejar enteros arbitrariamente grandes con aritmética exacta, Sage usa su propio tipo, llamado `Integer
<../reference/rings_standard/sage/rings/integer.html#sage.rings.integer.Integer>`_.
Una lista ( list ) es una estructura de datos que agrupa valores. Se construye usando corchetes como en [1, 3, 4]
. La función `range()
<https://docs.python.org/library/functions.html#range>`_ crea listas de enteros. También es posible crear listas usando comprensiones de listas: [ for in (if ) ]
. Por ejemplo:
In [ ]:
[ i^2 for i in range(10) if i % 2 == 0 ]
()
o mediante la construcción `tuple
<https://docs.python.org/library/functions.html#tuple>$_. Si una tupla tiene un solo elemento, se debe escribir $$(a,)$`. Una tupla es inmutable (no se puede cambiar) pero es enumerable (hashable - ver abajo). También es posible crear tuplas usando comprensiones de listas:
In [ ]:
tuple(i^2 for i in range(10) if i % 2 == 0)
Un conjunto ( set) es una estructura de datos que contiene valores sin multiplicidad u orden. Se crea a partir de una lista (o cualquier iterable) con el constructor set
. Los elementos de un conjunto deben ser enumerables (hashable):
In [ ]:
set([2,2,1,4,5])
In [ ]:
set([ [1], [2] ])
dict
, o usando la sintaxis:
In [ ]:
{ clave1 : valor1, clave2 : valor2 ...}
Por ejemplo:
In [ ]:
age = {'toto' : 8, 'mom' : 27}; age
' '
o dobles " "
) delimitan cadenas de caracteres. Se pueden concatenar usando \+
.l[i]
. También es posible sacar " tajadas " ( slices )de listas, tuplas y cadenas, l[:]
, l[:b]
, l[a:]
, or l[a:b]
. Indices negativos empiezan por el final.len()
https://docs.python.org/library/functions.html#len devuelve el numbero de elementos de una lista, tupla, conjunto, cadena o diccionario.Se escribe x in C
para verificar si x
está en C
.None.
En Python no hay delimitador para el comienzo y el final de un bloque de instrucciones. Los bloques son delimitados solamente mediante sangrías (indentation). Por lo general un bloque nuevo se introduce mediante :
. Python posee las siguientes estructuras de control:
In [ ]:
a = 1
In [ ]:
if a == 1:
print "yes"
In [ ]:
if a == 2:
print "no"
else:
print "yes"
In [ ]:
if a == 2:
print "no"
elif a == 1:
print "yes"
else:
print "no"
In [ ]:
l = [1,2,3,4,5]
In [ ]:
for v in l:
print v
In [ ]:
i = 1
while i < 500:
print i
i = i*2
continue
salta a la siguiente iteración.En lo que sigue trabajaremos con funciones en el sentido de lenguajes de la programación. Las funciones matemáticas, así como se manipulan en cálculo, son manejadas por Sage en una forma diferente. En particular, no tiene sentido hacer manipulaciones matemáticas como la adición o la diferenciación en funciones de Python.
Se define una función usando la llave def
:
In [ ]:
def myfunction(a):
return a*a
In [ ]:
myfunction(4)
El resultado de una función se genera mediante la instrucción return
. Las funciones muy cortas pueden crearse anónimamente, usando lambda
(observe que no hay instrucción return
):
In [ ]:
myfunction = lambda x: x*x
In [ ]:
myfunction(4)
Las funciones son objectos como cualquier otro. se pueden asignar a variables o devolver en una definicion. Para detalles vea el tutorial sobre Functional Programming for Mathematicians.
Ejemplo:
In [ ]:
L = [3, Permutation([5,1,4,2,3]), 17, 17, 3, 51]
L
Ejercicio:
Cree la lista [63,12,−10,"a",12]
, asígnela a la variable L
e imprímala
In [ ]:
# editar aquí
Ejercicio: cree la lista vacía (se usa frecuentemente)
In [ ]:
# editar aquí
La función range()
https://docs.python.org/library/functions.html#range (rango) es una forma sencilla de construir listas de enteros. Esta es una traducción de la documentación de la función `range()
https://docs.python.org/library/functions.html#range :
range([inicio,] fin[, paso])
In [ ]:
range(10)
In [ ]:
range(3,10)
In [ ]:
range(4,10,2)
Devuelve una lista que contiene una progresión aritmética de enteros.
range(i,j) devuelve $\[i,i+1,ldots,j-1\]$ el valor por defecto de start (!) es 0.
Cuando se ingresa un valor en paso, se especifica el incremento (o decremento)
Por ejemplo, range(4) devuelve $\[0, 1, 2, 3\]$. El punto final es omitido!
Estos números coinciden con los indices válidos para una lista de
4 elementos
Ejercicio: use range()
https://docs.python.org/library/functions.html#range para construir la lista $[1, \ldots, 50]$
In [ ]:
# editar aquí
Ejercicio: use para construir la lista de numeros enteros entre el 1 y el 100 (inclusive)
In [ ]:
# editar aquí
El argumento step
del comando`range()
https://docs.python.org/library/functions.html#range puede ser negativo. Use range()
para construir la lista $[10, 7, 4, 1, -2]$
In [ ]:
# editar aquí
Ver también:
`xrange()
<https://docs.python.org/library/functions.html#xrange>`_ : devuelve un iterador en lugar de construir una lista.`srange()
<../reference/misc/sage/arith/srange.html#sage.arith.srange.srange>`_ : similar a range pero con enteros de Sage; ver abajo.`xsrange()
<../reference/misc/sage/arith/srange.html#sage.arith.srange.xsrange>`_ : similar a xrange pero con enteros de Sage.Las comprensiones de listas son una forma concisa de crear listas a partir de otras listas (u otros tipos de datos).
Ejemplo: ya sabemos como crear la lista $[1,\ldots, 16]$ :
In [ ]:
range(1,17)
Usando una comprensión de lista, a ahora podemos crear la lista $[1^2, 2^2, \ldots , 16^2]$
In [ ]:
[i^2 for i in range(1,17)]
In [ ]:
sum([i^2 for i in range(1,17)])
Ejercicio: [ Projecto Euler, Problema 6 ]
La suma de los primeros 10 números naturales es:
$$1^2+2^2+\ldots+10^2=385$$El cuadrado de la suma de los primeros 10 números naturales es:
$$(1+2+\ldots + 10)^2 = 3025$$La diferencia entre estos números es:
$$3025-385=2640$$Encuentre la diferencia entre la suma de los cuadrados de los primeros 100 números y el cuadrado de la suma.
In [ ]:
# editar aquí
In [ ]:
# editar aquí
In [ ]:
# editar aquí
In [ ]:
[p^2 for p in [1,2,..,100] if is_prime(p)]
Ejercicio: Use una comprensión de lista para listar todos los números naturales menores que 20 que son múltiplos de 3 o 5. Pista:
Para obtener el residuo de 7 dividido entre 3 use 7%3
.
Para verificar la igualdad use dos signos igual( ==
); por ejemplo, 3 == 7
.
Projecto Euler, Problema 1 : Encuentre la suma de todos los múltiplos de 3 o 5 menores o iguales que 1000.
In [ ]:
# editar aquí
In [ ]:
[(x,y) for x in range(5) for y in range(3)]
In [ ]:
[[i^j for j in range(1,4)] for i in range(6)]
In [ ]:
matrix([[i^j for j in range(1,4)] for i in range(6)])
Exercise:
In [ ]:
# editar aquí
In [ ]:
# editar aquí
In [ ]:
# editar aquí
In [ ]:
# editar aquí
L[1]
?
In [ ]:
# editar aquí
L
?
In [ ]:
# editar aquí
L [\-1]
? qué es L [\-2]
?
In [ ]:
# editar aquí
L.index(2)
? qué es L.index(3)
?
In [ ]:
# editar aquí
In [ ]:
L = ["a", 4, 1, 8]
L
In [ ]:
L[2] = 0
L
In [ ]:
L = ["a", 4, 1, 8]
L
In [ ]:
L.append(17)
L
Para extender una lista con otra lista:
In [ ]:
L1 = [1,2,3]
L2 = [7,8,9,0]
print L1
print L2
In [ ]:
L1.extend(L2)
L1
In [ ]:
L = [4,2,5,1,3]
L
In [ ]:
L.reverse()
L
In [ ]:
L.sort()
L
In [ ]:
L = [3,1,6,4]
sorted(L)
In [ ]:
L
In [ ]:
L1 = [1,2,3]
L2 = [7,8,9,0]
L1 + L2
Se puede tajar una lista usando la sintaxis L[start : stop : step]
. Esto devolverá una sublista de L
.
Ejercicio: A continuación hay algunos ejemplos de tajadas de listas. Intente adivinar el resultado antes de evaluar la celda:
In [ ]:
L = range(20)
L
In [ ]:
L[3:15]
In [ ]:
L[3:15:2]
In [ ]:
L[15:3:-1]
In [ ]:
L[:4]
In [ ]:
L[:]
In [ ]:
L[::-1]
Ejercicio (Avanzado): La siguiente función combina un bucle con algunas de las operaciónes sobre listas mencionadas hasta ahora. Qué hace la función?
In [ ]:
def f(number_of_iterations):
L = [1]
for n in range(2, number_of_iterations):
L = [sum(L[:i]) for i in range(n-1, -1, -1)]
return numerical_approx(2*L[0]*len(L)/sum(L), digits=50)
In [ ]:
# editar aquí
In [ ]:
t = (3, 5, [3,1], (17,[2,3],17), 4)
t
Para crear una tupla con un solo elemento, se requiere una coma para eliminar la ambigüedad:
In [ ]:
(1)
In [ ]:
(1,)
Podemos crear una tupla a partir de una lista y viceversa:
In [ ]:
tuple(range(5))
In [ ]:
list(t)
Las tuplas se comportan como las listas en muchos respectos:
Operación | Sintaxis para listas | Sintaxis para tuplas |
---|---|---|
Acceder a un elemento | list[3] |
tuple[3] |
Concatenación | list1 \+ list2 |
tuple1 \+ tuple2 |
Tajado | list[3:17:2] |
tuple[3:17:2] |
Copia inversa | list[::\-1] |
tuple[::\-1] |
Longitud | len(list) |
len(tuple) |
No es posible modificar una tupla:
In [ ]:
t = (5, 'a', 6/5)
t
In [ ]:
t[1] = 'b'
Las “comprensiones de tuplas” no existen. En lugar de eso, la sintaxis produce algo llamado un generador. Un generador permite procesar una secuencia de ítems uno a la vez. Cada ítem se crea cuando se necesita y después se elimina. Esto puede ser bastante eficiente si cada ítem debe ser usado solo una vez.
In [ ]:
(i^2 for i in range(5))
In [ ]:
g = (i^2 for i in range(5))
g[0]
In [ ]:
[x for x in g]
g
ahora está vacía.
In [ ]:
[x for x in g]
Un truco pitónico chévere es usar generadores como argumentos de funciones. No necesitamos doble paréntesis para esto.
In [ ]:
sum( i^2 for i in srange(100001) )
Un diccionario es otro tipo de datos incorporado. A diferencia de las listas, que son indexadas por un rango de números que empiezan en 0, los diccionarios son indexados por llaves, que pueden ser cualquier objeto inmutable. Las cadenas de texto y los números siempre pueden usarse como llaves (porque son inmutables). En otros lenguajes de programación, a veces se llama a los diccionarios "arreglos asociativos"
Hay varias formas de definir diccionarios. Un metodo es usando llaves (corchetes redondos), {}
, con entradas separadas por comas escritas como llave:valor :
In [ ]:
d = {3:17, 0.5:[4,1,5,2,3], 0:"goo", 3/2 : 17}
d
Otro método es usando el constructor dict,
que admite una lista (o cualquier iterable) de 2-tuplas (llave, valor) :
In [ ]:
dd = dict((i,i^2) for i in xrange(10))
dd
Los diccionarios se comportan como listas y tuplas en varias operaciones importantes.
Operación | Sintaxis para listas | Sintaxis para diccionarios |
---|---|---|
Acceder elementos | list[3] |
D["key"] |
Longitud | len(list) |
len(D) |
Modificación | L[3] = 17 |
D["key"] = 17 |
Eliminación de elementos | del L[3] |
del D["key"] |
In [ ]:
d[10]='a'
d
Un diccionario puede tener el mismo valor repetido varias veces, pero cada llave debe aparecer solo una vez y debe ser inmutable:
In [ ]:
d = {3: 14, 4: 14}
d
In [ ]:
d = {3: 13, 3: 14}
d
In [ ]:
d = {[1,2,3] : 12}
Otra forma de adicionar elementos a un diccionario es con el método update()
, que actualiza el diccionario a partir de otro diccionario:
In [ ]:
d = {}
d
In [ ]:
d.update({10 : 'newvalue', 20: 'newervalue', 3: 14, 0.5:[1,2,3]})
d
Podemos iterar sobre las llaves, los valores, o ambos de un diccionario. Observe que internamente no se realiza ningún sorteo de las llaves. En general, el orden de las llaves/valores dependerá en localizaciones en memoria, y difiere entre computadores diferentes y/o ejecuciones en el mismo computador. Al imprimir, Sage sortea las entradas del diccionario por llaves, específicamente para hacer los resultados más reproducibles. Sin embargo, los métodos keys()
y values()
no sortean. Si que su salida sea reproducible, debe sortearla primero, como en los ejemplos a continuación:
In [ ]:
d = {10 : 'newvalue', 20: 'newervalue', 3: 14, 0.5:(1,2,3)}
In [ ]:
sorted([key for key in d])
In [ ]:
d.keys() # random order
In [ ]:
sorted(d.keys())
In [ ]:
d.values() # random order
In [ ]:
set(d.values()) == set([14, (1, 2, 3), 'newvalue', 'newervalue'])
In [ ]:
d.items() # random order
In [ ]:
sorted([(key, value) for key, value in d.items()])
Ejercicio: Considere el siguiente grafo dirigido.
Cree un diccionario cuyas llaves son los vértices de éste grafo, y cuyos valores son las listas de vertices a los que el vértice apunta. Por ejemplo, el vertice 1 apunta a los vértices 2 y 3, así que el diccionario tiene la forma:
In [ ]:
d = { ..., 1:[2,3], ... }
In [ ]:
# editar aquí
Después intente:
In [ ]:
g = DiGraph(d)
g.plot()
In [ ]:
matrix([[ i/j for j in range(1,4)] for i in range(1,4)])
Por otra parte, dividir un Entero http://doc.sagemath.org/html/en/reference/rings_standard/sage/rings/integer.html de Sage por un Entero de Sage produce un número racional:
In [ ]:
matrix([[ i/j for j in srange(1,4)] for i in srange(1,4)])
La modificación de listas tiene sus consecuencias!
Intente producir los resultados de los siguientes comandos:
In [ ]:
a = [1, 2, 3]
L = [a, a, a]
L
In [ ]:
a.append(4)
L
Ahora intente:
In [ ]:
a = [1, 2, 3]
L = [a, a, a]
L
In [ ]:
a = [1, 2, 3, 4]
L
In [ ]:
L[0].append(4)
L
Esto es conocido como el efecto referencia. Se puede usar el comando deepcopy()
https://docs.python.org/library/copy.html#copy.deepcopy para evitar este efecto:
In [ ]:
a = [1,2,3]
L = [deepcopy(a), deepcopy(a)]
L
In [ ]:
a.append(4)
L
El mismo efecto ocurre con diccionarios:
In [ ]:
d = {1:'a', 2:'b', 3:'c'}
dd = d
d.update( { 4:'d' } )
dd
Para una explicación más charlada de esto, una buena referencia es esta seccion del tutorial de Python: http://docs.python.org/tutorial/controlflow.html http://docs.python.org/tutorial/controlflow.html
Los bucles while no se usan tanto como los bucles for en código de Python:
In [ ]:
i = 0
while i < 10:
print i
i += 1
In [ ]:
i = 0
while i < 10:
if i % 2 == 1:
i+=1
continue
print i
i+=1
Observe que el valor de verdad de la expresión de cláusula en el bucle while
se evalua usando bool
:
In [ ]:
bool(True)
In [ ]:
bool('a')
In [ ]:
bool(1)
In [ ]:
bool(0)
In [ ]:
i = 4
while i:
print i
i -= 1
In [ ]:
l = ['a', 'b', 'c']
for letter in l:
print letter
La función range()
https://docs.python.org/library/functions.html#range es muy útil cuando desea generar progresiones aritméticas para recorrer en un bucle. Observe que el punto final nunca se incluye:
In [ ]:
range?
In [ ]:
range(4)
In [ ]:
range(1, 5)
In [ ]:
range(1, 11, 2)
In [ ]:
range(10, 0, -1)
In [ ]:
for i in range(4):
print i, i*i
Para saltar inmediatamente al siguiente paso en la iteración, se usa la palabra continue:
In [ ]:
for i in range(10):
if i % 2 == 0:
continue
print i
Para salir del bucle, use el comando break
In [ ]:
for i in range(10):
if i % 2 == 0:
continue
if i == 7:
break
print i
Si necesita registrar la posición en la lista y su valor, una forma de hacerlo (no muy elegante) es así:
In [ ]:
l = ['a', 'b', 'c']
for i in range(len(l)):
print i, l[i]
Una forma más limpia es usando enumerate()
https://docs.python.org/library/functions.html#enumerate , que provee tanto el índice como el valor:
In [ ]:
l = ['a', 'b', 'c']
for i, letter in enumerate(l):
print i, letter
Los bucles for
funcionan el protocolo de iteración de Python. Esto permite hacer bucles sobre diversas clases de objetos. Por ejemplo:
In [ ]:
for i in GF(5):
print i, i*i
Cómo funciona esto?
In [ ]:
it = iter(GF(5)); it
In [ ]:
next(it)
In [ ]:
next(it)
In [ ]:
next(it)
In [ ]:
next(it)
In [ ]:
next(it)
In [ ]:
next(it)
In [ ]:
R = GF(5)
R.__iter__??
El comando yield
es una forma muy conveniente de producir iteradores. Más adelante veremos más al respecto.
Para cada uno de los siguientes conjuntos, construya una lista con sus elementos y compute su suma. Use dos formas diferentes, si es posible: con un bucle y con una comprensión de lista.
In [ ]:
# editar aquí
In [ ]:
# editar aquí
In [ ]:
# editar aquí
In [ ]:
# editar aqui
Los primeros $n$ enteros que no son divisibles por 2, por 3 ni por 5.
In [ ]:
# editar aquí
In [ ]:
def f(x):
return x*x
In [ ]:
f(2)
Las funciones pueden ser recursivas:
In [ ]:
def fib(n):
if n <= 1:
return 1
else:
return fib(n-1) + fib(n-2)
In [ ]:
[fib(i) for i in range(10)]
Las funciones son objetos de primera clase como cualquier otro. Por ejemplo, se pueden pasar como argumentos a otras functiones:
In [ ]:
f
In [ ]:
def compose(f, x, n): # computa f(f(...f(x)))
for i in range(n):
x = f(x) # este cambio es local en esta llamada de la función!
return x
In [ ]:
compose(f, 2, 3)
In [ ]:
def add_one(x):
return x + 1
In [ ]:
compose(add_one, 2, 3)
Se pueden definir valores por defecto para argumentos de funciones:
In [ ]:
def add_n(x, n=1):
return x + n
In [ ]:
add_n(4)
In [ ]:
add_n(4, n=100)
In [ ]:
add_n(4, 1000)
Una función puede devolver múltiples valores:
In [ ]:
def g(x):
return x, x*x
In [ ]:
g(2)
In [ ]:
type(g)
In [ ]:
a,b = g(100)
In [ ]:
a
In [ ]:
b
Es posible definir funciones con un número variable de argumentos y argumentos keyword:
In [ ]:
def h(*args, **kwds):
print type(args), args
print type(kwds), kwds
In [ ]:
h(1,2,3,n=4)
Usemos la instrucción yield para hacer un generador de los números de Fibonacci hasta el número $n$ :
In [ ]:
def fib_gen(n):
if n < 1:
return
a = b = 1
yield b
while b < n:
yield b
a, b = b, b+a
In [ ]:
for i in fib_gen(50):
print i
is_even
, que devuelve True
si n
es par y False
de lo contrario.every_other
, que recibe una lista l
como argumento y devuelve una lista con los elementos intercalados de l
(uno sí y el siguiente no).every_other
, que recibe un iterable l
como entrada y devuelve los elementos de l
intercalados, uno después del otro.
In [ ]: