Apuntes, proyectos y códigos realizados con Python.
Python es sin duda un lenguaje que permite hacer muchas cosas, por lo que también es bastante extenso y en está sección lo descubriremos
- Recursos
- Pensamiento Computacional
- Python
- Aplicaciones de Python
- Lenguajes de programación
- Clasificación de tipado de lenguaje
- Paradigmas de programación
- Algoritmos
- El Zen de Python
- La consola
- Elementos básicos
- Variables y expresiones
- Asiganción de variables
- Operaciones en cadenas
- Entrada de datos
- Ramificación de programas
- Iteraciones
- Ayuda de Python
- Con variables
- Con funciones
- Strings y String literals
- String interning
- ASCII vs Unicode
- Representaciones de flotantes
- Funciones, alcance y abstracción
- Tipos estructurados, mutabilidad y funciones de alto nivel
- Estructuras de datos
- Pruebas y debugging
- Exepciones y afirmaciones
- POO
- Context managers
- Decoradores
- Librerias interesantes
- Ambientes virtuales
- Manejo de archivos con Python
- Graficado
- Tipado estático en Python
- Números flotantes en profundidad
- Manejo de fechas
- Time
- XPath
Complejidad
https://wiki.python.org/moin/TimeComplexity https://hacks.mozilla.org/2020/05/
https://docs.python.org/3/tutorial/datastructures.html
Profiler
building-functiontrace-a-graphical-python-profiler/?utm_source=dev-newsletter&utm_medium=email&utm_campaign=may28-2020&utm_content=profiler
- Conocimiento declarativo
- Formula matemática
- Conocimiento imperativo
- Cómo llegar a un resultado
- Algoritmos (Lista finita de instrucciones de describen un computo que se ejecuta con ciertas entradas y ejecuta pasos intermedios para llegar a un resultado)
- Lenguajes de programación
- Sintaxis (Secuencia de símbolos bien formada)
- Semántica estática (Define que enunciados con sintaxis correcta tiene significado)
- Semantica (Define el significado. Sólo hay un significado)
- Alto nivel o bajo nivel
- General o de dominio específico
- Interpretado o compilado
https://www.toptal.com/python/por-que-hay-tantos-pythons
https://speakerdeck.com/pablotrinidad
https://github.com/python/cpython/blob/master/Objects/listobject.c
https://alexgaynor.net/2010/may/15/pypy-future-python/
- Astropy
- Biopython
- Sympy
- Numpy
- Pandas
- Matplotlib
- Scipy
- Sunpy
- Tomopy
- aws
- gcloud
- rebound
- geeknote
- Django
- Flask
- Bottle
- Chalice
- Webapp2
- Gunicorn
- Tornado
https://instagram-engineering.com/web-service-efficiency-at-instagram-with-python-4976d078e366
Creo que todo empezó porque los primeros que trabajaron en Google (Sergey, Larry, Craig, …) tomaron una buena decisión de ingenieria: «Python donde podemos, C++ donde debemos.»
https://stackoverflow.com/questions/2560310/heavy-usage-of-python-at-google/2561008#2561008
Spotify
https://engineering.atspotify.com/2013/03/20/how-we-use-python-at-spotify/
Netflix
https://netflixtechblog.com/python-at-netflix-86b6028b3b3e
Uber
https://eng.uber.com/tech-stack-part-one-foundation/
Dropbox
https://www.pythonpeople.nl/how-python-powers-dropbox/
Pinteres
https://stackshare.io/pinterest/pinterest
Instacart
https://stackshare.io/posts/the-tech-behind-instacarts-grocery-delivery-service
https://brainsik.net/2009/why-reddit-uses-python/
Lyft
https://www.youtube.com/watch?v=aetoXWRt24k
Instrucciones que se convierten a código de maquina
Clasificación de un valor dentro del lenguaje
- Tipado Estatico. Los errores que tienen que ver con tipos son elevados en tiempo de compilación
- Tipado Dinamico. Elevan los errores de tipos en tiempo de ejecusión
- Tipado fuerte. No se pueden combinar distintos tipos de datos
- Tipado debil. Se pueden combinar distintos tipos de datos
Paradigma: Una manera de hacer las cosas
Hay dos estilos de programación,
- Imperativos: Los de la vieja escuela que son los imperativos. Indican que pasos y secuencia deben seguir los programas
- Programación procedimental: Desgloza algoritmos en porciones más manejables, como rutinas, funciones o subprogramas. Assembly, Basic
- Programación estructurada: orientado a mejorar la claridad, calidad y tiempo de desarrollo de un programa, recurriendo únicamente a subrutinas y tres estructuras básicas: secuencia, selección (if y switch) e iteración (bucles for y while). C
- Programación orientada a objetos: Usa objetos y sus interacciones, para diseñar aplicaciones y programas informáticos Está basado en varias técnicas, incluyendo herencia, abstracción, polimorfismo y encapsulamiento. Java, C++
- Programación modular: Divide el código por bloques parciales e independientes adaptandose a los requerimientos de proyectos de software, permitiendo pruebas individuales Java, Python
- Programación paralela: Instrucciones ejecutadas en multiples procesadores o hilos
- Declarativos: que son los modernos. Describen la solución o el resultado sin tomar en cuenta pasos intermedios
- Programación funcional: Son llamadas a funciones concatenadas, dónde cada parte del programa es interpretado por una función. Cloud Functions, Serverless, Aws Lambda, cualquier lenguaje
- Programación lógica: Se basa en la lógica matemática, en lugar de una serie de instrucciones, tienen un conjunto de principios (hechos/suposiciones) aplicando reglas para alcanzar el resultado Prolog, Python, R
- Programación basada en datos: Basada en la metodología Data Driven. SQL
https://www.ionos.mx/digitalguide/paginas-web/desarrollo-web/paradigmas-de-programacion/ https://www.geeksforgeeks.org/introduction-of-programming-paradigms/
- Serie de pasos ordenados
- Finito
- No es ambiguo
- Hermoso es mejor que feo.
- Explícito es mejor que implícito.
- Simple es mejor que complejo.
- Complejo es mejor que complicado.
- Sencillo es mejor que anidado.
- Escaso es mejor que denso.
- La legibilidad cuenta.
- Los casos especiales no son lo suficientemente * Especiales para romper las reglas.
- Lo práctico le gana a la pureza.
- Los errores no debe pasar en silencio.
- A menos que sean silenciados.
- En cara a la ambigüedad, rechazar la tentación de adivinar.
- Debe haber una - y preferiblemente sólo una - manera obvia de hacerlo.
- Aunque esa manera puede no ser obvia en un primer momento a menos que seas holandés.
- Ahora es mejor que nunca.
- Aunque “nunca” es a menudo mejor que “ahora mismo”.
- Si la aplicación es difícil de explicar, es una mala idea.
- Si la aplicación es fácil de explicar, puede ser una buena idea.
- Los espacios de nombres son una gran idea ¡hay que hacer más de eso!
Comandos principales
- cd navegar
- ls listar
- mkdir crear carpeta
- touch crear archivos
-
Literales
-
Operadores
-
Objetos
-
Tipos de dato
-
Escalares vs no escalares
a = 2
- Pueden contener números y letras
- Pueden reasignarse cuantas veces se necesite
- No pueden comenzar con numeros
- No se pueden utilizar las palabras reservadas de Python como variable.
- Se utiliza snake_case (guión bajo) para dividir las * palabras de las variables multipalabra
Expresiones son instrucciones para el interprete para evaluar la expresión. Los enunciados tienen efectos dentro del programa, como print que genera un output.
| 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 |
CONSTANTES: Una variable toda en mayuscula no debería de modificarse
_privada: Single Leading Underscore: _var : una variable que empieza con guion bajo ( “_” )
se deberá tratar como _privada y no se deberá de acceder fuera de la clase
__importante: Double Leading Underscore:__
variables que empiezan con doble guion bajo ( “__”) son variables importantes, si se llegara a modificar es provable que se pierda estabilidad del programa, así que mejor no tocarla mucho
var_: Single Trailing Underscore: var_: A veces, el nombre más apropiado para una variable lo toma una palabra clave. Por lo tanto, los nombres como class o def no se pueden usar como nombres de variables en Python.
En este caso, puede agregar un solo guión bajo ("_") para romper el conflicto de nombres: main: Double Leading and Trailing Underscore: var:
Las variables rodeadas por un prefijo de subrayado doble y un postfix quedan reservadas por el intérprete de Python.
- Parentesis
- Exponenciales
- Multiplicación
- División
- Adición
- Substracción
Operador de asignación (=)
base = 2
altura = 4
area = (base * altura) / 2
Las variables deben tener nombres que signifiquen algo para los humanos
* y +
# Formato de cadenas
f'{"Hip "*3} hurra'
# Acceso
my_str = 'Hola'
len(my_str)
my_str[0]
# Las últimas 2
my_str[2:]
# Primeras 3
my_str[3:]
# Sin las últimas 2
my_str[:-2]
# Saltando de dos en dos
my_str[::2]
# Cadenas
'Hola' + ' mundo'
f'{my_str} mundo' * 100
Crear una operación de forma eficiente con una computadora
numero = input('Escribe un número: ')
type(numero)
numero = int(input('Escribe un número: '))
if <condicion>:
<expresion> :
elif <condicion>:
<expresion>
else:
<expresion>
contador = 0
while contador < 10:
print(contador)
contador += 1
if(contador == 3):
break
frutas = ['manzana', 'pera', 'mango']
for fruta in frutas:
print(fruta)
# iterables
iter('cadena') # cadena
iter(['a', 'b', 'c']) # lista
iter(('a', 'b', 'c')) # tupla
iter({'a', 'b', 'c'}) # conjunto
iter({'a': 1, 'b': 2, 'c': 3}) # diccionario
Todas las llamadas anteriores regresan un objeto de tipo iterator.
Un iterator es un objeto que regresa sucesivamente los valores asociados con el iterable.
Un iterador es por ejemplo
for i in range(10):
print(i)
frutas = ['manzana', 'pera', 'mango']
iterador = iter(frutas)
next(iterador)
next(iterador)
next(iterador)
Son una forma rápida de crear iterables sin la necesidad de declarar una clase que implemente el protocolo de iteración. Para crear un generator simplemente declaramos una función y utilizamos el keyword yield en vez de return para regresar el siguiente valor en una iteración.
Es importante recalcar que una vez se ha agotado un generator ya no podemos utilizarlo y debemos crear una nueva instancia
def fibonacci(max):
a, b = 0, 1
while a < max:
yield a
a, b = b, a+b
fib1 = fibonacci(20)
fib_nums = [num for num in fib1]
double_fib_nums = [num * 2 for num in fib1]
double_fib_nums = [num * 2 for num in fibonacci(30)]
Para ver que podemos hacer con un String, basta con poner:
Ejemplo:
a = 'Hola'
dir(a)
Para ver la documentación
help(len)
Para tus propias funciones usa docstring
def m():
"""Este es un texto de ayuda para la función"""
pass
Son cadenas con funciones especiales, una cadena es inmutable
mystr1 = 'cadena'
mystr2 = "cadena"
mystr3 = """
esto es un texto con varias
lineas
en el código
"""
mystr1[1]
Permite jugar con rangos, el tercer campo es para saltos, y también puede indicar que sea todo al revés
mystr1[1]
mystr1[1:]
mystr1[1:3]
mystr1[1:6:2]
mystr1[::-1]
Longitud
len(mystr1)
Strip limpia de caracteres
mystr1.strip()
lower (es más sencilla) / casefold (forza todo a minuscula para cualquier idioma)
mystr1.lower()
mystr1.casefold()
upper
mystr1.upper()
capitalize (primera letra a mayuscula de la oración) / title (todas las palabras)
mystr1.capitalize()
mystr1.title()
replace
mystr1.replace('a','uo')
split parte con un separador
mystr1.split(',')
center para uso en terminal, undica cuantos caracteres y rellena con un caracter
mystr1.center(30,'-')
count cuenta apariciones de un caracter
mystr1.count('l')
endswith / startwith
mystr1.endswith('ld')
mystr1.startwith('ld')
find / index -1 indica que no encontro el substring con index falla
mystr1.find('a')
mystr1.index('a')
isMethods() retorna verdadero o falso
mystr1.isalpha() # solo letras
mystr1.isnumeric()
mystr1.isidentifier()
mystr1.isspace()
mystr1.islower()
mystr1.isupper()
mystr1.istitle()
join es el opuesto a split
separator = ' '
mylist = ['1','2','3']
print(mylist)
ex = separator.join(mylist)
print(ex)
Python maneja la memoria de forma dinámica siguiendo ciertas convenciones
a = 'Cody'
b = 'Cody'
a is b
# True
id(a)
id(b)
c = 'Cody!'
d = 'Cody!'
c is d
# False
Para que esto se gestione debe de seguirse al menos una de las siguientes reglas
- Todos los strings longitud 0 o longitud 1 serán interning.
- Los strings los cuales no están compuestos por letras de código ASCII, dígitos o guiones bajos no será interning.
- Ambos son codificadores de caracteres
- ASCII (American Standart Code for Information Interchange) toma en cuenta solamente el lenguaje inglés
- UNICODE incluye la mayoria de alfabetos del mundo
Python 3 por defecto usa Unicode
Problema Python para decimales
Abstracción: No se necesita saber como funciona algo para poder operarlo. Decomposición: Dividir algo en componentes que colaboren con un fin común
- Tienen un tipo
- Se pueden pasar como argumentos de otras funciones
- Se pueden utilizar en expresiones
- Se pueden incluir en estructuras de datos
def suma(a,b):
total = a + b
print(total)
return total
suma(2,2)
lambda <vars> : <expresion>
Son funciones de una única instrucción de código, en una única línea.
def mifuncion(nombre):
return "Hola %s!" % nombre
mifuncion = lambda nombre: "Hola %s!" % nombre
Devuelve una lista sin modificar la original
sorted()
Modifica la lista
lista.sort()
Se pueden pasar argumentos dinámicos a las funciones para evitar crear varias funciones de un mismo tipo
def suma2(n, n2):
return n + n2
def suma3(n, n2, n3):
return n + n2 + n3
def suma4(valor_uno):
print(valor_uno)
suma4(valor_uno=4)
- *args: n valores -> tuplas
- **kwargs: n valores -> diccionarios1
# Crea una tupla
def sumadinamica(*argumento):
print(argumento)
print(type(argumento))
def sumadinamica2(*args):
resultado = 0
for valor in args:
resultado += valor
return resultado
# Crea un diccionario
def sumadinamica3(**kwargs):
valor = kwargs.get('valor','No contiene el valor')
print(valor)
resultado = sumadinamica3(valor='Eduardo', x=2, y=9, z=True)
print(resultado)
Documentar docstrings en el código
def suma(a,b):
""" Suma dos valores a y b.
param int a cualquier entero
param int b cualquier entero
returns la sumatoria de a y b
"""
total = a + b
print(total)
return total
Ver documentación:
help(suma)
Es una forma de crear soluciones con el principio de divide y venceras. Es una técnica mediante la cual una función es llamada a si misma
Todas las combinaciones posibles
n! = n * (n - 1)!
def factorial(n):
"""Calcula el factorial de n
n int > 0
return n!
"""
if n == 1:
return 1
return n * factorial(n - 1)
Python restringe el número de veces que puede hacer recursividad, al momento de hacer este ejemplo permitió hasta el número 998
def fibonacci(n):
if n == 0 or n == 1:
return 1
a = fibonacci(n - 1) + fibonacci(n - 2)
print(a)
return a
- Son secuencias inmutables de objetos
- Son secuencias de valores indexadas por enteros
- Se crean separando los valores por comas
- Se encierran los valores por parentesis
- Pueden contener cualquier tipo de objeto
Se pueden utilizar para devolver más de un valor en una función o crear estructuras de datos ligeras
- También se puede usar la función
tuple
my_tuple = (1, 'dos', True)
my_tuple[0]
my_tuple(1,)
my_other_tuple = (2, 3, 4)
my_tuple += my_other_tuple
x, y, z = my_other_tuple
def coordenadas():
return(5, 4)
coordenada = coordenadas()
x, y = coordenadas()
a = (1,2,3,1,1,1,2,3,4)
dir(a)
a.count(2)
a.count(1)
a.index(1)
a.index(3)
- Representan una secuencia de enteros
range(comienzo,fin,pasos)
- Son inmutables
- Eficientes en uso de memoria y utilizados en for loops
my_range = range(1, 5)
for i in my_range:
print(i)
my_range = range(0,7,2)
my_other_range = range(0,8,2)
my_range == my_other_range
id(my_range)
my_range is my_other_range
for i in range(0, 101, 2):
print(i)
Nos permiten agrupar de distintas maneras varios valores y elementos para poderlos manipular con mayor facilidad
- Son secuencias de objetos, pero mutables
- Cuándo modificas unas lista, pueden existir efectos secundarios
- Es posible iterar con ellas
- Se pueden asignar via indice
- Utilizar métodos: append, pop, remove, insert
Se inician con []
o con la built-in function list
my_list = [1,2,3]
my_list[0]
my_list.append(4)
my_list[0] = 'a'
my_list.pop()
for element in my_list:
print(element)
a = [1,2,3]
b = a
id(a)
id(b)
c = [a , b]
a.append(5)
c
import copy
a = [1,2,3,4]
b = copy.copy(a)
a[0] = 0
a
b
lista = ['a']
lista2 = lista * 10
lista2
Suma (+) Concatena dos o más listas:
a=[1,2]
b=[3,4]
a + b --> [1,2,3,4]
Multiplicación (*) Repite la misma lista:
a=[1,2]
a * 2 —> [1,2,1,2]
Añadir elemento al final de la lista:
a=[1]
a.append(2)=[1,2]
Eliminar elemento al final de la lista:
a=[1,2]
b=a.pop()
a=[1]
Eliminar elemento dado un indice:
a=[1,2]
b=a.pop(1)
a=[2]
Ordenar lista de menor a mayor, esto modifica la lista inicial
a=[3,8,1]
a.sort() —> [1,3,8]
Ordenar lista de menor a mayor, esto NO modifica la lista inicial
a=[3,8,1]
a.sorted() —> [1,3,8]
Eliminar elementos de lista Elimina el elemento de la lista dado su indice
a=[1,2,3]
del a[0] —> a[2,3]
Eliminar elementos de lista Elimina el elemento de la lista dado su valor
a=[0, 2, 4, 6, 8]
a.remove(6)
a=[0, 2, 4, 8]
Range creacion de listas en un rango determinado
a=(list(range(0,10,2))) -->crea un conteo desde 0 hasta 10 en pasos de 2 en 2.
a=[0,2,4,6,8]
Tamaño lista len Devuelve el valor del tamaño de la lista:
a=[0,2,4,6,8]
len(a)=5
Al igual que con los strings las listas se pueden rebanar
lista = [1,2,3,4,5,6]
lista[1:]
lista[1:3]
lista[1:6:2]
lista[::-1]
lista = ['juan','pedro','pepe']
lista[0] = 'laura'
lista.append('estela')
nombre = lista.pop()
nombre == 'estela'
- Casi siempre es mejor clonar una lista en vez de mutarla
- Para ello podemos usar slices o la funcion list
a = [1,2,3]
b = a
id(a)
id(b)
c = list(a)
d = a[::]
Son similares a las listas pero no permiten elementos repetidos
- (S) y (T), teoria de conjuntos
- Se inicializan con la función
set
- Para añadir elementos se usa
add
- Para eliminar se usa
remove
a = set{[1,2,3]}
b = {3,4,5}
type(a)
type(b)
a.add(3)
a.add(20)
a.remove(20)
dir(a)
- Unión. Todos los elementos
- Intersección. Elementos en común
- Diferencia. Elementos que no se comparten
s = set([1,2,3])
t = set([]3,4,5)
s.union(t)
s.intersection(t)
s.difference(t)
1 in s
1 not in s
Es mejor realizar operaciones con conjuntos que con listas
Son mapas de llaves a valores. Los valores pueden ser de cualquier tipo
- Se crean con llaves o con el keyword dict
- Se añaden elementos al diccionario señalando la llave y el valor
- Son como listas, pero en lugar de indices se utilizan mapas
- No tienen orden interno
- Son mutables
- Pueden iterarse
d = {}
d['llave'] = 'valor'
d.get('helado',None)
d.keys()
d.values()
d.items()
- Al iterar de forma predeterminada se obtienen las llaves
- Es posible iterar sobre los valores
- Se pueden obtener llaves y valores al mismo tiempo
d = {}
d['primero'] = 'Hola'
d['segundo'] = 'adios'
d['primero']
for element in dict.keys():
print(element)
for element in dict.values():
print(element)
for element in dict.items():
print(element)
'David' in dict
'Tom' in dict
Son constructors que nos permiten generar una secuencia a partir de otra secuencia
- Forma concisa de aplicar operaciones a los valores de una secuencia
- También se pueden mostrar condiciones para filtrar
- Sintaxis más natural
[element for element in element_list if condition]
pares = [x for x in range(100) if x % 2 == 0]
nones = [x for x in range(100) if x % 2 != 0]
cuadrados = {x: x**2 for x in range(100)}
my_list = list(range(100))
double = [i * 2 for i in my_list]
double
pares = [i for i in my_list if i % 2 == 0]
pares
{key: element for element in element_list if condition}
student_uid = [1,2,3]
students = ['juan','pedro','jose']
students_with_uid = {uid: student for uid, student in zip(student_uid, students)}
{element for element in element_list if condition}
import random
random_numbers = []
for i in range(10):
random_numbers.append(random.randint(1,3))
non_repeat = {number for number in random_numbers}
El módulo collections nos proveé otros tipos o mejoras de las colecciones clásicas
from collections import Counter
l = [1,2,3,4,1,2,3,1,2,1]
Counter(l)
Counter("palabra")
animales = "gato perro canario perro canario perro"
c = Counter(animales.split())
print(c.most_common(1)) # Primeros elementos más repetidos
print(c.most_common(2)) # Primeros dos elementos más repetidos
print(c.most_common()) # Ordenados por repeticiones
l = [10,20,30,40,10,20,30,10,20,10]
c = Counter(l)
print(c.items())
print(c.keys())
print(c.values())
print(sum(c.values()))
print(list(c))
print(dict(c))
print(set(c))
La clase OrderedDict
es otra subclase de diccionario, pero está vez con la capacidad de conservar el orden en que añadimos los registros
from collections import OrderedDict
n = OrderedDict()
n['uno'] = 'one'
n['dos'] = 'two'
n['tres'] = 'three'
print(n)
# con diccionarios normales
n1 = {}
n1['uno'] = 'one'
n1['dos'] = 'two'
n2 = {}
n2['dos'] = 'two'
n2['uno'] = 'one'
print(n1 == n2) # Los elementos aparentemente están en el mismo orden
n1 = OrderedDict()
n1['uno'] = 'one'
n1['dos'] = 'two'
n2 = OrderedDict()
n2['dos'] = 'two'
n2['uno'] = 'one'
print(n1 == n2) # Los elementos aparentemente están en el mismo orden
NamedTuple es utilizada para crear pequeñas estructuras inmutables parecidas a una clase y sus objetos, pero mucho más simples:
from collections import namedtuple
Persona = namedtuple('Persona', ('nombre apellido edad'))
p = Persona(nombre='Hector', apellido='Costa', edad=27)
print(p)
# Son accesibles como objetos o por indices
print(p.nombre)
print(p.edad)
print(p[0])
print(p[-1])
Coffee = collection.NamedTuple('Coffee', ('Size','Bean', 'Price'))
def get_coffee(cofee_type):
if coffee_type == 'HouseBlend':
return Coffee('large','premium',10)
class SecretDict(collections.UserDict):
def _password_is_valid(self, password):
pass
def _get_item(self, key):
pass
def __getitem__(self, key):
password, key.split(':')
if self._password_is_valid(password):
return self._get_item(key)
return None
my_secret_dict = SecretDict(...)
my_secret_dict['password:key']
- Se basan en la especificación de la función o el programa
- Prueba inputs y valida outputs
- Unit testing o integration testing
- Se basan en el flujo del programa
- Prueba todos los caminos posibles de una función: Ramificaciones, bucles for y while, recursión
- Regression testing o mocks
- No te molestes con el debugger. Aprende a utilizar el print statement.
- Estudia los datos disponibles
- Utiliza los datos para crear hipótesis y experimentos. Método científico
- Ten una mente abierta. Si entendieras el programa, probablemente no habrían buggs
- LLeva un registro de lo que has tratado, preferentemente en la forma de test
- Debuggear es un proceso de búsqueda. Cada prueba debe acotar el espacio de busqueda
- Búsqueda binaria con print statements
- Encuentra los sospechosos comunes
- En lugar de preguntarte por qué un programa no funciona preguntate por que está funcionando de está manera
- Es posible que el bug no se encuentre donde crees que está
- Explicale el problema a otra persona. De preferencia que no tenga contexto
- Lleva un registro de lo que has tratado, preferentemente en la forma de test
- Vete a dormir
Programación defensiva
- Son muy comunes en la programación. No tienen nada excepcional
- Se relacionan con errores de semántica
- Se pueden crear excepciones propias
- Cuándo una excepción no se maneja, el programa termina en error
- Cuando se avienta (throw) un error, si el error no se atrapa el programa se detiene
- Se manejan con
try, except, else, finally
- Se pueden utilizar también para ramificar programas
- No deben manejarse de manera silenciosa (con print statement)
- Para aventar tu propia excepción utiliza el keyword
raise
def divide(numerador,denominador):
if denominador == 0:
raise ZeroDivisionError
try:
airplane.takeoff()
except TakeOffError as error:
airplane.land()
Necesitamos extender de BaseException
class TakeOffError(BaseException):
pass
La razón de usarlo en lugar del if es por EAFP(easier to ask for forgiveness than permission) Mientras que otros lenguajes utilizan LBYL(look before you leap)
// Javascript
/*
* Paises es un objeto. Pais es la llave
* Código con el principio LBYL
*/
function buscaPais(paises, pais){
if(!Object.keys(paises).includes(paises)){
return null
}
return paises[pais];
}
Python maneja una jerarquia de errores
https://docs.python.org/3.5/reference/compound_stmts.html#try
try:
# run this code
pass
except:
# execute this code when there is an exception
pass
else:
# no exceptions? Run this code
pass
finally:
# Always run this code
pass
- Programación defensiva
- Pueden utilizarse pra verificar que los tipos sean correctos en una función
- Sirven para debuguear
Otorga los medios para estructurar programas de tal manera que las propiedades y comportamientos esten envueltos en objetos individuales
La clave es pensar en objetos como agrupaciones de datos y los métodos que operan en dichos datos. Estos pueden tener propiedades y comportamientos.
La programación orientada a objetos nos permite modelar cosas reales y concretas del mundo y sus relaciones con otros objetos
Principios básicos:
- Encapsulación
- Abstracción
- Herencia
- Polimorfismo
Es la forma de acceder al objeto en memoria y el name es el nombre que se le da al objeto, ya sean variables o funciones
my_var = 5
id(my_var)
id(5)
Es un conjunto de names, existe una relación que liga los nombre definidos con sus respectivos objetos. Por ejemplo, existe un namespace especifico que agrupa todas las variables globales (por eso pueden utilizarse varias funciones sin tener que importar los modulos correspondientes), cada vez que declaramos un módulo o una función, dicho módulo o función tiene asignado otro namespace
Scope es la parte del programa en el que podemos tener acceso a un namespace sin necesidad de prefijos
- Scope dentro de una funcion (con nombres locales)
- Scope del modulo (con nombres globales)
- Scope raíz (que tiene los built in names)
Python busca los objetos primero en el scope local, luego en el global y por último en el raíz
def outer_function(some_local_name):
def inner_function(other_local_name):
# Tiene acceso a la built-in function print y al nombre local some_local_name
print(some_local_name)
# También tiene acceso a su scope local
print(other_local_name)
Para poder manipular una variable que se encuentra fuera del scope local podemos utilizar los keywords global y nonlocal
some_var_in_other_scope = 10
def some_function():
global some_var_in_other_scope
some_var_in_other_scope += 1
- Sirven para definir cosas complejas
- Permiten organizar el código
- Sólo proveen estructura
- Pueden tener variables de clase, instancia y locales
- Aunque python no maneja variables privadas es común declararlas con
_
- Para determinar si pertenece a una clase especifica
isinstance
o si tiene un atributo específicohasattr
- Casi toda clase debe tener el metodo
__init_
o__str__
Mientras que las clases proveen la estrucutra, las instancias son los objetos reales que creamos en nuestro programa: un hotel llamado Hilton
Otra forma de pensarlo es que las clases son como un formulario y una vez que se llena cada copia del formulario tenemos las instancias que pertenecen a cada clase. Cada copia puede tener datos distintos. Al igual que cada instancia es distinta a las demás
- Los atributos de clase nos permiten
- Representar datos
- Procedimientos para interactuar con los métodos
- Esconder la representación interna
- Se accede a los atributos con la notación de punto
- Puede tener atributos privados. Por convención comienza con _
class Hotel
pass
Una vez teniendo la clase, podemos generar una instancia llamando al constructor de la clase
hotel = Hotel()
Todas las clases crean objetos y todos los objetos tienen atributos. Se usa el método especial __init__
para definir el estado inicial de la instancia. Recibe como primer parametro obligatorio self
(es simplemente una referencia a la instancia)
class Hotel:
def __init__(self, numero_maximo_de_huespedes, lugares_de_estacionamiento):
self.numero_maximo_de_huespedes = numero_maximo_de_huespedes
self.lugares_de_estacionamiento = lugares_de_estacionamiento
self.huespedes = 0
hotel = Hotel(numero_maximo_de_huespedes=50, lugares_de_estacionamiento=20)
print(hotel.lugares_de_estacionamiento)
Mientras que los atributos de la instancia describen lo que representa el objeto, los métodos de instancia nos indican que podemos hacer con las instancias de dicha clase y normalmente operan en los mencionados atributos.
Los métodos son equivalentes a funciones dentro de la definición de la clase, pero todos reciben self
como primer argumento
-
Todo es un objeto en Python y tiene un tipo
- Representan datos y formas de interactuar con ellos
-
Formas de interactuar con un objeto
- Creación
- Manipulación
- Destrucción
-
Ventajas
- Decomposición
- Abstracción
- Encapsulación
- Partir un problema en problemas más pequeños
- Las clases permiten crear mayores abstracciones en forma de componentes
- Cada clase se encarga de una parte del problema y el programa se vuelve más fácil de mantener
- Enfocarnos en la información relevante
- Separar la información central de los detalles
- Podemos utilizar variables y métodos (privados o públicos)
- Permite agrupar datos y su comportamiento
- Controlar el acceso a dichos datos
- Previene modificaciones no autorizadas
- Esconde la complejidad
- Permite modelar jerarquias de clases (Arbol)
- Permite compartir comportamiento común
- Al padre se le conoce como Superclase y al hijo como SubClase
- Habilidad de tomar varias formas
- Nos permite cambiar el comportamiento de una superclase para adaptarlo a la subclase
Son objetos de Python que proveen información contextual adicioal al bloque de código. Consiste en correr una función (o cualquier callable) cuando se inicia el contexto con el keyword with; al igual que correr otra función cuando el código dentro del bloque with concluye
with open('some_file.txt') as f:
lines = f.readlines()
Existen dos formas de implementar un context manager:
- Con una clase
- Con un generador
class CustomOpen(object):
def __init__(self, filename):
self.file = open(filename)
def __enter__(self):
return self.file
def __exit__(self, ctx_type, ctx_value, ctx_traceback)
self.file.close()
with CustomOpen('file') as f:
contents = f.read()
El ejemplo anterior es una clase con dos métodos adicionales enter y exit. Estos métodos son utilizados por el keyword with para determinar las acciones de inicialización, entrada y salida del contexto
El mismo código puede implementarse usando el módulo contextlib que forma parte de la librería estándar de Python
from contextlib import contextmanager
@contextmanager
def custom_open(filename):
f = open(filename)
try:
yield f
finally:
f.close()
with custom_open('file') as f
contents = f.read()
Yield retorna una secuencia de valores y no un valor final
- Permite agregar mayor funcionalidad a una función
- Un decorador es una función que recibe otra función y regresa una tercera función.
- Para reconocer un decorador, puedes ver que tienes un arroba sobre la declaración de una función.
A, B y C son funciones A recibe como parametro B para poder crear C
Click es un framework que nos permite crear aplicaciones de línea de comandos
- Utiliza decoradores para implementar su funcionalidad
- @click.group
- @click.command
- @click.argument
- @click.option
- Nos otorga una interfaz personalizable
- Realiza las conversiones de tipo por nosotros
La documentación oficial se puede ver aquí
https://click.palletsprojects.com/en/7.x/
Es una pizarra para poder dibujar
https://opentechschool.github.io/python-beginners/es_CL/simple_drawing.html
- Permiten aislar el ambiente para poder instalar diversas versiones de paquetes
- A partir de Python 3 se incluye en la libreria estandar en el modulo venv
- Ningún ingeniero profesional de Python trabaja sin ellos
- Permite descargar paquetes de terceros para utilizar en nuestro programa
- Permite compartir nuestros paquetes con terceros
- Permite especificar la version del paquete que necesitamos
# Python 3 ya tiene virtualenv en el core, ya no es necesario instalarlo
pip install virtualenv
virtualenv env
# Forma actual
python -m venv env
cd env
cd Scripts
activate.bat
pip install bokeh
pip freeze
deactivate
python3 freeze
En Python es posible tener las dependencias en un fichero requirements.txt
pip install -r requirements.txt
- Python puede leer y escribir con la funcion
open
f = open('file')
- Es importante cerrar el archivo para que se guarden los datos y no se desperdicie memoria
f.close()
- La funcion open regresa un objeto de tipo archivo (file)
- El archivo se debe cerrar con el método close
Está función permite garantizar que el archivo se cierre de forma automática
with open(filename) as f:
# do something with the file
Existen varios metodos para abrir un archivo se específica con el atributo mode=''
dentro de open
- Se tiene que especificar el modo en que se maneja el archivo
- 'r' = read
- 'w' = write
- 'a' = append
- 'r+' = read and write
Nos permite manipular archivos separados por comas
- Almacena archivos de forma tabular
- Basta con importarlo
import csv
Existen dos readers y dos writers
- csv.reader y csv.writer, permiten manipular los valores a través de listas que representan filas
- Solo se puede acceder por indice a los valores
- csv.DictReader y csv.DictWriter nos permiten maniplar los valores a través de diccionarios que representan filas
- Se puede acceder a traves de llaves a los valores
- Reconocimiento de patrones
- Predicción de una serie
- Simplifica la interpretación y las conclusiones acerca de los datos
- Bokeh permite construir gráficas complejas de manera rápida con comando simples
- Permite exportar a varios formatos como html, notebooks, imagenes
- Bokeh se puede utilizar en el servidor con Flask y Django
La computadora no trabaja con números decimales, sino con binarios
print(0.1+0.1+0.1 == 0.3)
Base 10 vs Base 2 25 = 11001
Aplica a cualquier base 25 = 2x10^1 + 5x10^0
El número máximo que se puede representar con n bits es (2^n)-1
Para números decimales
Para representar 0.1
Las computadoras no pueden representar el número exacto, el estándar es representarlo hasta la cantidad de bits del procesador
Se puede resolver mediante formateo de Strings
- Decimal: implementa la aritmética decimal de forma exacta, para aplicaciones de alta precisión
- Fractions: implementa la representación de números fraccionarios como 1/3 de manera exacta
- Numpy que es externa
https://docs.python.org/3/tutorial/floatingpoint.html
Python dispone de un módulo
import datetime
my_time = datetime.datetime.now()
print(my_time)
my_day = datetime.date.today()
print(my_day)
my_birthday = datetime.date(1999,12,20)
print(my_birthday)
Tiempo (segundos) transcurrido desde UNIX 1 enero de 1970, estándart de tiempo para las computadoras
my_timestamp = datetime.date.fromtimestamp(1588048333)
print(my_timestamp)
Sirve para realizar mediciones específicas de tiempo
La variable isdst indica si está activo el uso horario
Hora a partir del horario universal
Crear una fecha
Fecha en un string
Formato
Genera el Structime que corresponde a la fecha
Diferencias con Time y Datetime
Datetime
- Trabajar con fechas / Operaciones
Time
- Mediciones de tiempo
- Es más fácil trabajar con el horario de verano
- TimestampUNIX
XML Path Language, el lenguage del web scraping profesional.
- Xpath es un lenguaje para encontrar información dentro de una respuesta.
- Selenium es un emulador del navegador web
Navegar entre los nodos
$x('/')
$x('/html/body')
Doble // indica un salto
$x('//span')
Predicados van en []
$x('//span[@class="text"]/text()')
$x('//span[@class="text"]/text()').map(x => x.wholeText)
$x('//div[contains(@class, "tags-box")]//a[@class="tag"]/text()').map(x=>x.wholeText)
https://www.amazon.com/s?k=python+books&__mk_es_US=%C3%85M%C3%85%C5%BD%C3%95%C3%91&ref=nb_sb_noss_2
Amazon:
$x('//h2/a[@class="a-link-normal a-text-normal"]/span[contains(@class, "a-text-normal")]/text()').map(x => x.wholeText)
El espectador:
$x('//div[contains(@class, "node-title") and @itemprop="name"]/h1/text()')[0]
$x('//div[contains(@class, "group-container")]//div[contains(@class, "node-image")]//img/@src').map(x => x.value)