Introducción a Python#
Tipos de Datos#
Uno de los elementos más importantes para definir un lenguaje de programación es la definición de los tipos de datos que ese lenguaje va a utilizar. Esos tipos de datos pueden ser desde muy simples como números o caracteres hasta hasta datos mucho más complejos como gráficos, archivos y demás.
A las variables hay que darles un nombre, y este es uno de los tres problemas más complejos de la informática:
There are only two hard things in Computer Science: cache invalidation and naming things. Phil Kartlon
De acuerdo a la guía de estilo de Python, el lenguaje adopta el estilo snake_case
, es decir que se identifican los datos con nombres en minúscula, separados por el guión bajo _
.
Por supuesto, está prohibido usar las palabras reservadas como nombres de datos:
and del for is raise assert if else elif from lambda return break global not try class except or while continue exec import yield def finally in print
Tipos numéricos, operaciones con tipos numéricos#
Números reales y enteros#
a = 7.584 # número real
print(a)
print(type(a))
b = 8 # número entero
print(b)
print(type(b))
c = 10 + 5j
print(c)
print(type(c))
7.584
<class 'float'>
8
<class 'int'>
(10+5j)
<class 'complex'>
Cast
d = float(b) # cast a float
print(d)
print(type(d))
e = int(a) # cast a int
print(e)
print(type(e))
f = complex(a)
print(f)
print(type(f))
print(f.real)
print(f.imag)
8.0
<class 'float'>
7
<class 'int'>
(7.584+0j)
<class 'complex'>
7.584
0.0
Python realiza un cast dinámico al realizar una operación. Por ejemplo, al sumar un float
y un int
, el int
es promovido a float
antes de sumar
d = a + b
print(d, type(d))
d = a - c
print(d, type(d))
15.584 <class 'float'>
(-2.4160000000000004-5j) <class 'complex'>
f = a*b
print(a, type(a))
print(b, type(b))
print(f, type(f))
7.584 <class 'float'>
8 <class 'int'>
60.672 <class 'float'>
En la división de dos enteros (usando /), se obtiene un float. Nota: esto no ocurria en Python 2.x, donde la división de dos enteros usando /, daba un entero.
Para recuperar la división de enteros, uso //.
a = 3
b = 2
c = a/b # <---- en python 2.x, la división de enteros con / da un entero
print(c, type(c))
c2 = a//b
print(c2, type(c2))
1.5 <class 'float'>
1 <class 'int'>
Potencias:
h = 3**2
print(h, type(h))
h1 = 3.0**2
print(h1, type(h1))
h2 = 3**2.0
print(h2, type(h2))
h3 = 3.0**2.0
print(h3, type(h3))
9 <class 'int'>
9.0 <class 'float'>
9.0 <class 'float'>
9.0 <class 'float'>
Modulo:
a = 11
b = 3
c = a%b
print(c, type(c))
a = 11.42
b = 3.21
c = a%b
print(c, type(c))
2 <class 'int'>
1.79 <class 'float'>
Otras operaciones con números:
from math import *
c = sqrt(9)
print(c)
d = floor(27.25)
print(d)
f = log(1000)
print(f)
f = cos(0)
print(f)
3.0
27
6.907755278982137
1.0
Constantes:
print(pi)
print(e)
3.141592653589793
2.718281828459045
math.sqrt(-1) # <--- no
---------------------------------------------------------------------------
NameError Traceback (most recent call last)
Cell In[10], line 1
----> 1 math.sqrt(-1)
NameError: name 'math' is not defined
Existe un modulo aparte para operaciones con complejos
import cmath
cmath.sqrt(-1)
z = 3.0 + 3.0j
print(z.real)
print(z.conjugate())
import math
print(cmath.phase(z))
print(math.degrees(cmath.phase(z)))
print(abs(z))
print(cmath.polar(z))
Tipos lógicos (bool)#
T = True
F = False
print(F)
print(type(F))
print(T*F)
print(2*T)
print("Hola", 23)
a = 28.2
b = a
print(b)
# # print('mayor/menor a: ', a < b)
c = 99.8
a = c
print(a)
print(b)
# print('igual a: ', a == b)
# print('distinto a: ', a != b)
# print('es: ', a is b)
# print('no es: ', a is not b)
Strings#
Un string es una secuencia de caracteres de cualquier tipo (letras, números, símbolos,…) que se definen usando comillas (simple o dobles.
a = "Este es un ejemplo de un string"
print(a)
print(type(a))
a
print(a)
b = 'donde podemos usar comillas simples'
c = "o usar comillas dobles"
print(b, c)
Podemos concatenar strings usando +
d = a + b + c + "y que podemos concatenar usando el signo '+', por ejemplo"
print(d)
f = 'También podemos usar "comillas dobles" dentro de comillas simple'
print(f)
g = "o 'al revés', como en este caso"
print(g)
Podemos agregar caracteres de formato:
h = "Siempre quise aprender\ncomo poner caracteres de formato\nen un string de Python.\n"
print(h)
j = "Supongamos que queremos hacer una lista que contenga los elementos:\n\t * elemento 1\n\t * elemento 2\n\t * and so on..."
print(j)
print('%s' % h)
print('%r' % h)
Un ejemplo de docstring:
m = '''
Acá puedo poner cuantas lineas
quiera, sin preocuparme si son dos
lineas, cuantro lineas, 6 lineas...
¿habrá algún límite?
'''
print(m)
Indexado (en strings)#
Un string es un ejemplo de ‘contenedor’ de elementos (en este caso, caracteres), a los cuales se puede acceder mediante el índice que indica su posición:
my_string = 'Hola mundo'
print(my_string[0])
print(my_string[4])
print(my_string[5])
print(my_string[10]) # mi índice no puede ser mayor a la cantidad de elementos
Se pueden utilizar índices negativos para acceder a los elementos, referidos al último. Es decir, el -1 es el último, el -2 es el penúltimo, y así por el estilo:
print(my_string[-1])
print(my_string[-2])
print(my_string[-10])
Slicing#
Puedo acceder a un subconjunto de elementos, utilizando una técnica conocida como “slicing”, donde, dado un string a, obtengo el subconjunto como a[inicio:fin:paso], (donde todos los argumentos son opcionales):
print(my_string[1:6])
sub_string = my_string[6:10]
print(sub_string)
print(my_string[0] + sub_string)
print(my_string[0:5])
print(my_string[:5])
print(my_string[5:10])
print(my_string[5:])
print(my_string[::2])
print(my_string[1::2])
print(my_string[::-2])
Algunos métodos de strings#
string_2 = "se viene el estallido, de mi guitarra, y tu gobierno, también"
print(string_2)
print(string_2.capitalize())
print(string_2.upper())
string_3 = string_2.upper()
print(string_3.lower())
k = string_2.find('est')
print(k)
print(string_2[k:])
N = string_2.count('i')
print(N)
N = string_2.count('ta')
print(N)
string_separado = string_2.split(',')
print(len(string_separado))
string_4 = string_2.replace(', ', '\n')
print(string_4)
string_separado_en_lineas = string_4.splitlines()
print(string_separado_en_lineas)
string_de_numeros = '123456789asfdsfds'
print(string_de_numeros.isnumeric())
print(string_de_numeros.isalpha())
print(string_de_numeros.isalnum())
Listas#
my_list = [4, 8, 15, 16, 23, 42]
print(type(my_list))
print(my_list)
<class 'list'>
[4, 8, 15, 16, 23, 42]
Las listas tambien son secuencias, por lo que el indexado y slicing funcionan como ya hemos visto con los strings
my_list[0]
4
my_list[::-1]
[42, 23, 16, 15, 8, 4]
Y pueden contener cualquier tipo de objetos:
nombre = 'Jack'
lista_heterogenea = [108, 'Dharma', my_list, nombre]
print(lista_heterogenea)
print(lista_heterogenea[2][0])
[108, 'Dharma', [4, 8, 15, 16, 23, 42], 'Jack']
4
Se pueden agregar elementos a una lista
lista_heterogenea.append('Shepard')
lista_heterogenea
[108, 323, [4, 8, 15, 16, 23, 42], 'Jack', 'Shepard', 'Shepard']
O se pueden reemplazar elementos
lista_heterogenea[1] = 323
lista_heterogenea
[108, 323, [4, 8, 15, 16, 23, 42], 'Jack', 'Shepard']
Incluso se pueden hacer asignaciones de secuencias sobres “slices”
lista_heterogenea[0:2] = ['A', 'B', 'C', 'D'] # notar que no hace falta que el valor tenga el mismo tamaño que el slice
lista_heterogenea
Otras operaciones entre listas:
print(4 in my_list)
print(4 not in my_list)
L = my_list + lista_heterogenea
print(L)
L = 3*my_list
print(L)
print(sum(my_list))
print(len(my_list))
print(min(my_list))
print(max(my_list))
print(lista_heterogenea.index('B'))
print(lista_heterogenea.count(42))
print(lista_heterogenea)
print(lista_heterogenea.count([4, 8, 15, 16, 23, 42]))
my_list = [4,8,15,16,23,42]
print(my_list)
otra_lista = my_list[::-1]
print(otra_lista)
print(my_list)
my_list.reverse()
print(my_list)
del my_list[1:3]
print(my_list)
list1 = [0,1,2]
list2 = list1
list2[0] = 8
print(list1)
print(list2)
Tuplas#
Las tuplas son iguales a las listas, con la diferencia es que las listas son mutables mientras las tuplas no.
una_tupla = ('Benjamin', 108, my_list, ('Linus', my_list[0]))
print(type(una_tupla))
print(una_tupla[1:3])
una_tupla
una_tupla.append('B')
una_tupla[-1] = 'osooo'
una_tupla.reverse()
Diccionarios#
La diccionarios son otro tipo de estructuras de alto nivel que ya vienen incorporados. A diferencia de las secuencias, los valores no están en una posición sino bajo una clave: son asociaciones clave:valor
stock = {'Manzanas': 1, 'Peras': 10, 'Bananas': 5, 'Frutillas': 'Fuera de temporada'}
stock
Accedemos al valor a traves de un clave
stock['Frutillas'] = 20
stock
stock['Sandía'] = 1
stock
del stock['Sandía']
stock
list(stock.items())[1][0]
list(stock.items())
list(stock.keys())
stock.values()
Control de flujo#
Una de las herramientas fundamentales de la programación es poder controlar los efectos sobre el programa cuando se cumplen ciertas condiciones, o poder repetir en forma sencilla una cantidad de operaciones. Estas instrucciones se disponen en estructuras que permiten manejar el flujo de un programa, y están presentes en todos los lenguajes de programación. Las más fundamentales se llaman prácticamente igual en la mayoría de los lenguajes.
Un aspecto importante que presentan las estructuras de flujo en Python es que requieren de indentación, esto es, dejar espacios de forma tal de que la estructura pueda quedar bien definida. Otra de las discusiones eternas de la computación es cuántos espacios se utilizan para indentar. La respuesta correcta en este curso es 4.
Condicionales#
Nota = 7
if Nota >= 8:
print ("Aprobó cómodo, felicidades!")
elif 6 <= Nota < 8:
print ("Bueno, al menos aprobó!")
elif 4 <= Nota < 6 :
print ("Bastante bien, pero no le alcanzó")
else:
print("Lo esperamos después de las vacaciones!")
En un if, la conversión a tipo boolean es implícita. El tipo None (vacío), el 0, una secuencia (lista, tupla, string) (o conjunto o diccionario, que ya veremos) vacía siempre evalua a False. Cualquier otro objeto evalua a True.
respuesta = 'lala'
if respuesta:
print('respondió!')
else:
print('no respondió!')
Iteraciones#
Loop for
for i in [0,1,2,3]:
print(i,i+1)
provincias_patagonicas = ["Tierra del Fuego", "Santa Cruz", "Chubut", "Neuquén", "Río Negro", "La Pampa"]
for provincia in provincias_patagonicas:
print(provincia)
sumatoria = 0
for elemento in [1, 2, 3.6]:
sumatoria += elemento
sumatoria
Iteradores#
Veremos un tipo nuevo, llamado range
, que es un iterador. Se crea mediante cualquiera de los siguientes llamados:
range(stop)
range(start, stop, step)
r = range(10)
print(r)
print(type(r))
r = list(range(10))
print(r)
print(type(r))
p = list(range(2,12,2))
print(p)
p = list(range(20,10,-2))
print(p)
for elemento in range(10):
print(elemento)
for (posicion, valor) in enumerate([4, 3, 19]):
print('El valor de la posicion', posicion, 'es', valor)
temp_min = [-3.2, -2, 0, -1, 4, -5, -2, 0, 4, 0]
temp_max = [13.2, 12, 13, 7, 18, 5, 11, 14, 10 , 10]
for t1, t2 in zip(temp_min, temp_max):
print('La temperatura mínima fue', t1, 'y la máxima fue', t2)
Control de flujo de loops#
Se puede salir del loop usando break
sumatoria = 0
for elemento in range(1000):
if elemento > 100:
break
sumatoria = sumatoria + elemento
sumatoria, elemento
sumatoria = 0
for elemento in range(101):
sumatoria += elemento
sumatoria, elemento
Se puede omitir un iteración usando continue
sumatoria = 0
for elemento in range(20):
if elemento % 2:
continue
print(elemento, end=', ')
sumatoria = sumatoria + elemento
sumatoria
Un ejemplo práctico, consiste en crear una lista a través de un loop:
cuadrados = []
for i in range(-3,15,1):
cuadrados.append(i**2)
print(cuadrados)
Loop while
a = 0
while a < 10:
print(a)
a += 1
n = 1
while True:
n = n + 1
print(n, 'elefantes se balanceaban sobre la tela de una araña')
continuar = input('Desea invitar a otro elefante?')
if continuar.lower() == 'no':
break
Imprimiendo con formato#
Si bien Python es bastante astuto al imprimir usando la instrucción print
, se puede dar formato a aquello que uno quiere imprimir. Hay una variedad de maneras de obtener una impresión agradable. Veamos un par de casos.
Usando %
#
Se utiliza el símbolo %
para definir el formato de cada variable. Veamos algunos ejemplos
s = 42
print("s (decimal): %d" % s)
print("s (decimal): %10.3d" % s)
print("s (octal) : %o" % s)
print("s (hexadecimal) : %x" % s)
s (decimal): 42
s (decimal): 042
s (octal) : 52
s (hexadecimal) : 2a
from math import *
golden_ratio = (1 + sqrt(5))/2
print(golden_ratio)
print("Golden Ratio = %5.2f" % golden_ratio) # un campo de 5 caracteres, con dos decimales
print("Golden Ratio = %5.3f Golden Ratio/100 = %8.3e" % (golden_ratio,golden_ratio/100)) # un campo de 5 caracteres, con tres decimales, notación exponencial
1.618033988749895
Golden Ratio = 1.62
Golden Ratio = 1.618 Golden Ratio/100 = 1.618e-02
Usando format
#
print("s (decimal): {0:d}" .format(s))
print("s (decimal): {0:10d}".format(s))
print("s (octal) : {0:o}".format(s))
print("s (hexadecimal) : {0:x}".format(s))
s (decimal): 42
s (decimal): 42
s (octal) : 52
s (hexadecimal) : 2a
print(golden_ratio)
print("Golden Ratio = {0:5.2f}" .format(golden_ratio)) # un campo de 5 caracteres, con dos decimales
print("Golden Ratio = {0:5.3f} Golden Ratio/100 = {1:8.3e}" .format(golden_ratio,golden_ratio/100)) # un campo de 5 caracteres, con tres decimales, notación exponencial
1.618033988749895
Golden Ratio = 1.62
Golden Ratio = 1.618 Golden Ratio/100 = 1.618e-02
El uso de format
también se llama posicional
print("Golden Ratio = {1:5.3f} Golden Ratio/100 = {0:8.3e}" .format(golden_ratio,golden_ratio/100)) # un campo de 5 caracteres, con tres decimales, notación exponencial
# un campo de 5 caracteres, con tres decimales, notación exponencial
Golden Ratio = 0.016 Golden Ratio/100 = 1.618e+00