Skip to content

Latest commit

 

History

History
1922 lines (1495 loc) · 48.3 KB

File metadata and controls

1922 lines (1495 loc) · 48.3 KB

Lenguaje Python

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

Tabla de Contenido

Recursos

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

Pensamiento Computacional

  • 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

Python

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/

Aplicaciones de Python

Ciencias

  • Astropy
  • Biopython
  • Sympy
  • Numpy
  • Pandas
  • Matplotlib
  • Scipy
  • Sunpy
  • Tomopy

CLI

  • aws
  • gcloud
  • rebound
  • geeknote

Aplicaciones web

  • Django
  • Flask
  • Bottle
  • Chalice
  • Webapp2
  • Gunicorn
  • Tornado

Empresas usando python

Instagram

https://instagram-engineering.com/web-service-efficiency-at-instagram-with-python-4976d078e366

Google

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

Reddit

https://brainsik.net/2009/why-reddit-uses-python/

Lyft

https://www.youtube.com/watch?v=aetoXWRt24k

Lenguajes de programación

Instrucciones que se convierten a código de maquina

Funciones nativas en Python

TIpos de datos

Clasificación de un valor dentro del lenguaje

Funciones nativas en Python

Tiempo de ejecusión

Funciones nativas en Python

Clasificación de tipado de lenguaje

  • Tipado Estatico. Los errores que tienen que ver con tipos son elevados en tiempo de compilación

Tipado Estatico

Typescript

Java

  • Tipado Dinamico. Elevan los errores de tipos en tiempo de ejecusión

Tipado dinamico

PHP

Python

  • Tipado fuerte. No se pueden combinar distintos tipos de datos

Python

  • Tipado debil. Se pueden combinar distintos tipos de datos

Js

PHP

Paradigmas de programación

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/

Algoritmos

  • Serie de pasos ordenados
  • Finito
  • No es ambiguo

El Zen de Python

  • 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!

La consola

Comandos principales

  • cd navegar
  • ls listar
  • mkdir crear carpeta
  • touch crear archivos

Elementos básicos

  • Literales

  • Operadores

  • Objetos

  • Tipos de dato

  • Escalares vs no escalares

    a = 2

Variables y expresiones

Reglas de Variables:

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

Palabras reservadas

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

Prioridad de operadores PEMDAS

  • Parentesis
  • Exponenciales
  • Multiplicación
  • División
  • Adición
  • Substracción

Asiganción de variables

Operador de asignación (=)

base = 2
altura = 4
area = (base * altura) / 2

Las variables deben tener nombres que signifiquen algo para los humanos

Operaciones en cadenas

* 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

Entrada de datos

numero = input('Escribe un número: ')
type(numero)
numero = int(input('Escribe un número: '))

Ramificación de programas

if <condicion>:
  <expresion> :
elif <condicion>:
  <expresion>
else:
  <expresion>

Iteraciones

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.

Iterators

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)

Generators

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

Ayuda de Python

Con variables

Para ver que podemos hacer con un String, basta con poner:

Ejemplo:

a = 'Hola' dir(a)

Con funciones

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

Strings y String literals

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

"""

Accediendo a elementos

mystr1[1]

Slices

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)

String Methods

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)

String interning

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.

ASCII vs Unicode

  • 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

Representaciones de flotantes

Problema Python para decimales

Funciones, alcance y abstracción

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

Funciones

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

Funciones anonimas (Lamdas)

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

Funciones en Python

Funciones nativas en Python

Función de ordenamiento

Devuelve una lista sin modificar la original sorted() Modifica la lista lista.sort()

Argumentos dinámicos

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)

Específicaciones de código

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)

Recursividad

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

Factorial

Todas las combinaciones posibles

Factorial metemático

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

Serie de fibbonachi

def fibonacci(n):
    if n == 0 or n == 1:
      return 1
    a = fibonacci(n - 1) + fibonacci(n - 2)
    print(a)
    return a

Tipos estructurados, mutabilidad y funciones de alto nivel

Tuplas

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

Rangos

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

Estructuras de datos

Nos permiten agrupar de distintas maneras varios valores y elementos para poderlos manipular con mayor facilidad

Listas y mutabilidad

  • 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

Copiar una lista

import copy
a = [1,2,3,4]
b = copy.copy(a)
a[0] = 0
a
b

Operaciones con listas

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

Listas con slices

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] 

Modificacion de listas

lista = ['juan','pedro','pepe']
lista[0] = 'laura'
lista.append('estela')
nombre = lista.pop()
nombre == 'estela'

Clonación

  • 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[::]

Sets o conjuntos

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)

Operaciones con sets

  • 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

Diccionarios

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

Iteración de diccionarios

  • 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

Comprehensions

Son constructors que nos permiten generar una secuencia a partir de otra secuencia

List comprehension

  • 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

Dictionary comprehensions

{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)}

Set comprehensions

{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}

Collections

El módulo collections nos proveé otros tipos o mejoras de las colecciones clásicas

Contadores

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

Otros usos

Diccionarios ordenados

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

Tuplas con nombre

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

Pruebas y debugging

Pruebas de caja negra

  • Se basan en la especificación de la función o el programa
  • Prueba inputs y valida outputs
  • Unit testing o integration testing

Pruebas de caja de cristal

  • 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

Debugging

  • 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

Diseño de experimentos

  • Debuggear es un proceso de búsqueda. Cada prueba debe acotar el espacio de busqueda
  • Búsqueda binaria con print statements

Errores comúnes

  • 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

Exepciones y afirmaciones

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

Manejo de excepciones

  • 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

Excepciones

def divide(numerador,denominador):
  if denominador == 0:
    raise ZeroDivisionError

try:
  airplane.takeoff()
except TakeOffError as error:
  airplane.land()

Generación de errores propios

Necesitamos extender de BaseException

class TakeOffError(BaseException):
  pass

Excepciones como control de flujo

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];
}

Jerarquía de errores

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

Afirmaciones

  • Programación defensiva
  • Pueden utilizarse pra verificar que los tipos sean correctos en una función
  • Sirven para debuguear

POO

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

Resumen

Identificadores

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)

Namespaces y Scope

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

Conceptos

Clases

  • 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ífico hasattr
  • Casi toda clase debe tener el metodo __init_ o __str__

Instancias

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

Atributos de la instancia

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)

Métodos de instancia

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

Tipos de datos abstractos

  • 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

Decomposició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

Abstracción

  • Enfocarnos en la información relevante
  • Separar la información central de los detalles
  • Podemos utilizar variables y métodos (privados o públicos)

Encapsulación

  • Permite agrupar datos y su comportamiento
  • Controlar el acceso a dichos datos
  • Previene modificaciones no autorizadas
  • Esconde la complejidad

Herencia

  • Permite modelar jerarquias de clases (Arbol)
  • Permite compartir comportamiento común
  • Al padre se le conoce como Superclase y al hijo como SubClase

Polimorfismo

  • Habilidad de tomar varias formas
  • Nos permite cambiar el comportamiento de una superclase para adaptarlo a la subclase

Context managers

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

Decoradores

  • 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

Framework CLick

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/

Librerias interesantes

Turtle

Es una pizarra para poder dibujar

https://opentechschool.github.io/python-beginners/es_CL/simple_drawing.html

Ambientes virtuales

  • 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

Pip

  • 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

Archivo de dependencias

En Python es posible tener las dependencias en un fichero requirements.txt

pip install -r requirements.txt

Manejo de archivos con Python

  • 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

Context Managers

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

Módulo CSV

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

Graficado

  • Reconocimiento de patrones
  • Predicción de una serie
  • Simplifica la interpretación y las conclusiones acerca de los datos

Gráficado simple

  • 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

Documentación de Bokeh

Tipado estático en Python

Números flotantes en profundidad

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

Decimal a binario

El número máximo que se puede representar con n bits es (2^n)-1

Para números decimales

Decimal a binario

Decimal a binario

Decimal a binario

Para representar 0.1

Decimal a binario

Las computadoras no pueden representar el número exacto, el estándar es representarlo hasta la cantidad de bits del procesador

Decimal a binario

Se puede resolver mediante formateo de Strings

Decimal a binario

Decimal a binario

Módulos útiles

  • 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

Manejo de fechas

Python dispone de un módulo

Módulo Datetime

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)

Timestamp

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)

Universal time coordinator (UTC)

Time

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

XPath

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

Probando en el navegador

http://quotes.toscrape.com/

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:

https://www.elespectador.com/tecnologia/alphabet-dice-adios-proyecto-de-ciudad-inteligente-en-toronto-articulo-918490

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