Sesión 1
Jesús Fernández (fernandez.cuesta@gmail.com)
1 Abril 2019
Creado en 1990 por Guido van Rossum
Definición y evolución del lenguaje recogido en PEPs (Python Enhancement Proposals)
import math
número = input("Introduce un número [0, 1, 2, ...]: ")
número = int(número) # convierte texto a número entero
print('El factorial de', número, 'es', math.factorial(número))
# de forma alternativa:
# print('El factorial de %s es %s' % (número, math.factorial(número)))
# print('El factorial de {} es {}'.format(número, math.factorial(número)))
# print(f'El factorial de {número} es {math.factorial(número)}')
python x.y.z
x: versión principal, incompatibles entre sí [2, 3]
y: versión secundaria, normalmente compatibles
z: versión menor (errores y seguridad)
Línea temporal de versiones, en rojo: versión obsoleta
Interfaces simples (pythonic)
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <err.h>
char response[] = "HTTP/1.1 200 OK\r\n"
"Content-Type: text/html; charset=UTF-8\r\n\r\n"
"Hello, world!\r\n";
int main()
{
int one = 1, client_fd;
struct sockaddr_in svr_addr, cli_addr;
socklen_t sin_len = sizeof(cli_addr);
int sock = socket(AF_INET, SOCK_STREAM, 0);
if (sock < 0)
err(1, "can't open socket");
setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(int));
int port = 8080;
svr_addr.sin_family = AF_INET;
svr_addr.sin_addr.s_addr = INADDR_ANY;
svr_addr.sin_port = htons(port);
if (bind(sock, (struct sockaddr *) &svr_addr, sizeof(svr_addr)) == -1) {
close(sock);
err(1, "Can't bind");
}
listen(sock, 5);
while (1) {
client_fd = accept(sock, (struct sockaddr *) &cli_addr, &sin_len);
if (client_fd == -1) {
perror("Can't accept");
continue;
}
write(client_fd, response, sizeof(response) - 1); /*-1:'\0'*/
close(client_fd);
}
}
No es necesario compilar…
python.exe
Anaconda Prompt > python
(> ipython
)
(p.e. pinterest, instagram, linkedin, …)
como “pegamento” entre componentes escritos en otros lenguajes
The 2018 Top Programming Languages, IEEE
gran soporte en foros, comunidades, conferencias, …
Worldwide, Python is the most popular language, Python grew the most in the last 5 years (PYPL)
fuente: stackoverflow
R
: muy enfocado en análisis estadísticoPython
: generalista, con librerías especializadas (pandas, scikit-learn, scipy, … )Diferentes distribuciones para Windows:
#!
)python
(p.e. ipython
, bpython
)jupyter
python.exe
).CPython
, PyPy
, Jython
, IronPython
…)n
” intérpretes distintos instalados en el sistema, cada uno con diferentes libreríasconda
: instala por defecto un entorno (intérprete) base
y un conjunto de librerías
Cada entorno tiene un único intérprete python + librerías
Por defecto partiremos de un entorno global/base
Regla general: evitar usar el intérprete global del sistema y el entorno
base
git
, librerías, …)base
Anaconda | Miniconda |
---|---|
~3GB disco | <400MB |
> 200 librerías | base + dependencias |
+ herramientas | ciclo distribución +rápido |
IDE (Spyder + VSCode) | |
Anaconda Navigator | sin interfaz gráfico |
↑ tiempo instalación |
Alternativas (más bajo nivel):
Determinar la plataforma sobre la que se va a instalar
https://www.anaconda.com/download/
con chocolatey
:
🕐 7-15 minutos
base
) con diferentes librerías instaladas, p.e.:pandas |
beautifulsoup4 |
requests |
jupyter |
scrapy |
matplotlib |
sqlalchemy |
numpy |
jsonschema |
seaborn |
Anaconda prompt
o acceder a la terminal desde vscodeCrear un entorno virtual con pandas
, scrapy
, jupyter
, bs4
y pyjstat
.
(base) > conda create --name entorno-01
(base) > conda create --name entorno-02 python=2.7 --yes
# crea entorno con paquetes preinstalados
(base) > conda create -n entorno-03 python=3.7 pandas scipy -y
Crear un entorno virtual con pandas
, scrapy
, jupyter
, bs4
y pyjstat
.
# instala librerías gestionadas por conda
(entorno 03) > conda install pandas scrapy jupyter bs4 --yes
pyjstat
no está dentro de los repositorios de conda
git
# exportar definición del entorno
(entorno-03) > conda list --export > requirements.txt # solo dependencias
(entorno-03) > conda env export > entorno-03.yml # entorno + dependencias
# salir del entorno (vuelve al entorno base)
(entorno-03) > conda deactivate
(base) >
Ctrl+Shift+P
)
ipython
/ python
o bien “Python: ejecutar REPL”base
)
flake8
;
’)#
»;
)import os
home = os.path.expanduser('~') # directorio del usuario
directorio = os.path.join(
home, 'Documentos', 'python'
)
ficheros = []
# Busca ficheros y guarda (nombre, tamaño)
for f in os.listdir(directorio):
ruta = os.path.join(directorio, f)
if os.path.isfile(ruta):
tamaño = os.stat(ruta).st_size
ficheros.append((f, tamaño))
print(f)
print(tamaño)
print("Total", len(ficheros), "ficheros")
¹ Generalmente con 4 espacios, no mezclar con tabuladores!!!
#
»#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
Descripción breve del programa.
Varias líneas delimitadas por 3 caracteres "
"""
import os
home = os.path.expanduser('~') # comentario en línea
directorio = os.path.join(
home, 'Documentos', 'python'
)
# Comentario
ficheros = [f for f in os.listdir(directorio)
if os.path.isfile(os.path.join(directorio, f))]
for f in ficheros:
print(f)
print(os.stat(os.join(directorio), f).st_size)
import
from pathlib import Path
home = Path.home() # pathlib.Path.home()
directorio = home / 'Documentos' / 'python'
def busca_ficheros(directorio):
return (
(f.name, f.stat().st_size) for f in directorio.iterdir() if f.is_file()
)
for (nombre, tamaño) in busca_ficheros(directorio):
print(f'Encontrado fichero {nombre} de {tamaño} Bytes')
Palabras reservadas
import builtins
import keyword
print(', '.join(keyword.kwlist))
False, None, True, and, as, assert, async, await, break, class,
continue, def, del, elif, else, except, finally, for, from,
global, if, import, in, is, lambda, nonlocal, not, or, pass,
raise, return, try, while, with, yield
print(dir(builtins))
['ArithmeticError', 'AssertionError', 'AttributeError', 'BaseException',
'BlockingIOError', 'BrokenPipeError', 'BufferError', 'BytesWarning',
'ChildProcessError', 'ConnectionAbortedError', 'ConnectionError',
'ConnectionRefusedError', 'ConnectionResetError', 'DeprecationWarning',
'EOFError', 'Ellipsis', 'EnvironmentError', 'Exception', 'False',
'FileExistsError', 'FileNotFoundError', 'FloatingPointError', 'FutureWarning',
'GeneratorExit', 'IOError', 'ImportError', 'ImportWarning', 'IndentationError',
'IndexError', 'InterruptedError', 'IsADirectoryError', 'KeyError',
'KeyboardInterrupt', 'LookupError', 'MemoryError', 'ModuleNotFoundError',
'NameError', 'None', 'NotADirectoryError', 'NotImplemented',
'NotImplementedError', 'OSError', 'OverflowError', 'PendingDeprecationWarning',
'PermissionError', 'ProcessLookupError', 'RecursionError', 'ReferenceError',
'ResourceWarning', 'RuntimeError', 'RuntimeWarning', 'StopAsyncIteration',
'StopIteration', 'SyntaxError', 'SyntaxWarning', 'SystemError', 'SystemExit',
'TabError', 'TimeoutError', 'True', 'TypeError', 'UnboundLocalError',
'UnicodeDecodeError', 'UnicodeEncodeError', 'UnicodeError',
'UnicodeTranslateError', 'UnicodeWarning', 'UserWarning', 'ValueError',
'Warning', 'ZeroDivisionError', '__IPYTHON__', '__build_class__', '__debug__',
'__doc__', '__import__', '__loader__', '__name__', '__package__', '__spec__',
'abs', 'all', 'any', 'ascii', 'bin', 'bool', 'breakpoint', 'bytearray',
'bytes', 'callable', 'chr', 'classmethod', 'compile', 'complex', 'copyright',
'credits', 'delattr', 'dict', 'dir', 'display', 'divmod', 'enumerate', 'eval',
'exec', 'filter', 'float', 'format', 'frozenset', 'get_ipython', 'getattr',
'globals', 'hasattr', 'hash', 'help', 'hex', 'id', 'input', 'int',
'isinstance', 'issubclass', 'iter', 'len', 'license', 'list', 'locals', 'map',
'max', 'memoryview', 'min', 'next', 'object', 'oct', 'open', 'ord', 'pow',
'print', 'property', 'range', 'repr', 'reversed', 'round', 'set', 'setattr',
'slice', 'sorted', 'staticmethod', 'str', 'sum', 'super', 'tuple', 'type',
'vars', 'zip']
if __name__ == "__main__":
Se llama a __main__()
cuando se ejecuta directamente:
import sys
import math
def area(radio):
return math.pi * (radio ** 2)
def longitud(radio):
return 2 * math.pi * radio
print('Hola mundo')
# entra aquí cuando se ejecuta desde un intérprete
if __name__ == "__main__":
radio = float(sys.argv[1]) # sys.argv[] son los argumentos de entrada
print(
"La longitud de una circunferencia de radio {}cm es {:.2f}cm^2."
.format(radio, longitud(radio))
)
print("El area de una circunferencia de radio {1}cm es {0:.2f}cm^2."
.format(area(radio), radio))
python
puede contener (entre otros) definiciones de constantes, variables, funciones o clases..py
en un árbol de directorios: principal/
__init__.py import principal
practica.py
recolector/ from principal import recolector
__init__.py
collector.py
database.py
conversor/
__init__.py
limpia.py
procesa.py
graficos/
__init__.py
graficos.py
exportar.py
string/
__init__.py
string.py
proyecto/
README.rst
LICENSE
setup.py
requirements.txt
entorno_conda.yml
ejemplo/__init__.py
ejemplo/core.py
ejemplo/helpers.py
docs/conf.py
docs/index.rst
tests/unitarios.py
tests/funcionales.py
nombre del paquete
descripción del proyecto
licencia [2]
distribución/empaquetado [3]
descripción de las dependencias
descripción del entorno
el código en sí
" "
" "
documentación del proyecto
" "
funciones de test del proyecto
" "
³ p.e. setuptools
Cómo importar módulos
Mal:
Algo mejor:
from numpy import array
from pandas import *
f = array([1, 2, 3, 4]) # seguro que ndarray es de numpy?
Bien:
Código estructurado por módulos/submódulos
principal/
__init__.py <-------- entrada al módulo principal
recolector/ <-----.
__init__.py |
collector.py --. |
database.py | |
conversor/ <-----' |
__init__.py |
limpia.py ----------'
procesa.py
collector.py
necesita importar conversor
, mientras que limpia.py
importa recolector
conversor
afectan a recolector
for
, if
)ipython
ipython
In[n]
identifica las entradas de comandosipython
)
%
’%run
, %matplotlib
, %load
, %who
Ctrl+R
activa la búsqueda en el historial
%hist
, %history
para visualizarlo_
guarda la salida del último comando &sup4;&sup4; _
se usa también como variable de usar/tirar, p.e. cuando una función devuelve varios resultados, pero solamente estamos interesados en uno.
[TAB]
autocompleta (p.e. import st[TAB]
)
math
math.radians
)**
o math.pow
)16/13
numpy
import numpy as np
pyplot
de la librería matplotlib
from matplotlib import pyplot as plt
a
de 1000 puntos entre [0, 1]
np.linspace()
np.sin()
np.pi
%matplotlib inline
a
en el eje x y 2 ⋅ π ⋅ a en el eje y
plt.plot()
:::
jupyter
Descargar el cuaderno de ejemplo en el directorio python
y ejecutar línea por línea.
(o bien ejecutarlo en forma remota con Binder)
Exportar entorno virtual
# exportar definición del entorno
# solo dependencias
(entorno-01) conda list --export > requirements.txt
# entorno + dependencias
(entorno-01) conda env export > entorno-01.yml
# o bien desde base
(base) conda env export --name entorno-01 > entorno-01.yml
pip
(requirements.txt
)
conda
Otros recursos en línea
pip
Pipfile
y Pipfile.lock
definen las dependencias
Pipfile.lock
para versiones específicas, evitando que se actualicenpipenv run ...
$ pipenv install bpython
$ pip install 'pandas==' # muestra versiones disponibles [OJO! pip]
$ pipenv install 'pandas==0.23.1' 'requests==2.2.1'
$ pipenv install 'lxml==3.*' # bloquea solamente la rama 3.x
$ pipenv install 'untangle==1.1.*' # bloquea versiones [major, minor]
$ pipenv install -r requirements.txt # instala desde un fichero requirements
$ pipenv lock -r > requirements.txt # exporta a fichero requirements
Para comprobar los paquetes instalados, mostrar el contenido de Pipfile
Otras funcionalidades útiles con pipenv:
Acceder al intérprete propio del entorno:
Ejecutar código cargando librerías propias del entorno:
# desinstala todos los paquetes no especificados en `Pipfile.lock`
$ pipenv clean
# destruye el entorno virtual
$ pipenv --rm
Restaura un entorno virtual desde los ficheros Pipfile
y Pipfile.lock
:
GC: Garbage Collector
Utiliza 2 algoritmos para la gestión de memoria:
foo = []
# 2 referencias, 1 de la variable foo y una de la llamada a getrefcount
print(sys.getrefcount(foo))
def bar(a):
# 4 referencias
# variable foo, argumento a función, getrefcount + pila interna de python
print(sys.getrefcount(a))
bar(foo)
# 2 referencias, se limpiaron las propias de la función
print(sys.getrefcount(foo))
multithread
)# multi_threaded.py
import time
from threading import Thread
COUNT = 50000000
def countdown(n):
while n>0:
n -= 1
thread_1 = Thread(target=countdown, args=(COUNT//2,))
thread_2 = Thread(target=countdown, args=(COUNT//2,))
start = time.time()
thread_1.start()
thread_2.start()
thread_1.join()
thread_2.join()
end = time.time()
print('Tiempo de ejecución {:.2f} segundos'.format(end - start))
multiprocess
)