Python Intermediate

Guillermo Vayá

guillermo.vaya@gigas.com

<2014-06-13 Fri>

Presentacion

Zen of python

import this

The Zen of Python, by Tim Peters

Beautiful is better than ugly.

Explicit is better than implicit.

Simple is better than complex.

Complex is better than complicated.

Flat is better than nested.

Sparse is better than dense.

Readability counts.

Special cases aren't special enough to break the rules.

Zen of python (II)

Although practicality beats purity.

Errors should never pass silently.

Unless explicitly silenced.

In the face of ambiguity, refuse the temptation to guess.

There should be one– and preferably only one –obvious way to do it.

Although that way may not be obvious at first unless you're Dutch.

Now is better than never.

Zen of python (III)

Although never is often better than right now.

If the implementation is hard to explain, it's a bad idea.

If the implementation is easy to explain, it may be a good idea.

Namespaces are one honking great idea – let's do more of those!

Algunos Tipos basicos

Hashes (diccionarios)

  • Par clave-valor
  • No tienen orden
  • Se recorren las claves

Ejemplo

>>> {'uno': 1, 'dos':2}
{'dos': 2, 'uno': 1}
>>> b = {'uno': 1, 'dos':2}
>>> b["uno"]
1
>>> b["tres"]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
KeyError: 'tres'
>>> b.get("tres", 3)
3
>>> "dos" in b
True
>>> "tres" in b
False
>>> b.keys()
['dos', 'uno']
>>> b.items()
[('dos', 2), ('uno', 1)]

Conjuntos

  • Conjunto: lista sin orden
  • Operaciones clasicas de conjuntos

Ejemplo

>>> c = {1,2,3}
>>> c
set([1, 2, 3])
>>> d = {3,4,5}
>>> c.union(d)
set([1, 2, 3, 4, 5])
>>> c.difference(d)
set([1, 2])
>>> c.intersection(d)
set([3])
>>> c.issubset(c.union(d))
True
>>> 2 in c
True
>>> 5 in c

Tuplas

  • inmutable
  • comportamiento identico a array
  • mas ligero en memoria
  • existen las named tuples
  • el operador es la , pero por claridad se ponen parentesis

Ejemplo

>>> t = (1,2,3)
>>> t[1]
2
>>> t[1:]
(2, 3)
>>> t[1]=2
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: 'tuple' object does not support item assignment

Unpack

Introspeccion

  • dir: permite revisar los metodos y atributos de un objeto
>>> dir(1)
[... '__init__', '__int__', '__invert__', '__long__', '__lshift__', '__mod__',
 '__mul__', '__neg__', '__new__', '__nonzero__', '__oct__', '__or__', '__pos__', 
 '__pow__', '__radd__', '__rand__', '__rdiv__', '__rdivmod__', '__reduce__', 
 '__reduce_ex__', '__repr__', '__rfloordiv__', '__rlshift__', '__rmod__', 
 '__rmul__', '__ror__', '__rpow__', '__rrshift__', '__rshift__', '__rsub__', 
 '__rtruediv__', '__rxor__', '__setattr__', '__sizeof__', '__str__', '__sub__',
 '__subclasshook__', '__truediv__', '__trunc__', '__xor__', 'bit_length', ....]
  • help: accede a la ayuda definida por el propio codigo
  • inspect: libreria especializada

Formateando strings

suma

  • concatenacion basica de cadenas
  • No recomendado
>>> "a" + "b"
'ab'
>>> "a" + 1
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: cannot concatenate 'str' and 'int' objects

porcentaje

  • En desuso
  • Mas versatil que la suma
    >>> "Hola %s" % 'Persona'
    'Hola Persona'
    >>> "Hay %.2f cosas" % 12.543
    'Hay 12.54 cosas'
    >>> "Hola %s" % 1
    'Hola 1'
    

format

  • Método recomendado (pero hay mucho codigo antiguo que no lo usa)
  • muy versatil
    >>> "{a} es de tipo {a.__class__}".format(a="hola")
    "hola es de tipo <type 'str'>"
    
    >>> "{} persona".format("hola")
    'hola persona
    

join

>>> ", ".join(["uno", "dos", "tres"])
'uno, dos, tres'

Funcional

lambda

  • funcion anonima
  • solo acepta una linea
  • util para pequeñas transformaciones
  • return implicito

map

  • aplica una funcion a una coleccion
  • en python 3 es un generador

filter

  • elimina elementos que no cumplan una condicion
  • en python 3 es un generador

reduce

  • aplica una operacion y guarda un acumulado
  • en python 3 ya no es builtin, sino que se importa de functools

Ejemplos

>>> (lambda x: x if x == 2 else 0)(5)
0
>>> (lambda x: x if x == 2 else 0)(2)
2
>>> map(lambda x: x+1, [1,2,3])
<map object at 0x7f19383b0550>
>>> list(map(lambda x: x+1, [1,2,3]))
[2, 3, 4]
>>> list(filter(lambda x: x % 2 == 1, [1,2,3]))
[1, 3]
>>> from functools import reduce
>>> reduce(lambda x, y: x + (y % 2), [1,2,3,4,5], 0)
3

Comprehensions

List

  • forma de generacion de listas
    >>> [x for x in range(1,10)]
    [1, 2, 3, 4, 5, 6, 7, 8, 9]
    
  • map
    >>> [x+1 for x in range(1,10)]
    [2, 3, 4, 5, 6, 7, 8, 9, 10]
    
  • filter
    >>> [x for x in range(1,10) if (x % 2)]
    [1, 3, 5, 7, 9]
    
  • encadenar es complicado
    >>> a = [(x, x+10) for x in range(1,10)]
    >>> a
    [(1, 11), (2, 12), (3, 13), (4, 14), (5, 15), (6, 16), (7, 17), (8, 18), (9, 19)]
    >>> [j for x in a for j in x]
    [1, 11, 2, 12, 3, 13, 4, 14, 5, 15, 6, 16, 7, 17, 8, 18, 9, 19]
    

Otros

  • dict comprehension
  • set comprehension
  • generator comprehension
>>> {x: x+10 for x in range(1,10)}
{1: 11, 2: 12, 3: 13, 4: 14, 5: 15, 6: 16, 7: 17, 8: 18, 9: 19}
>>> {x for x in range(1,10)}
{1, 2, 3, 4, 5, 6, 7, 8, 9}
>>> type({x for x in range(1,10)})
<class 'set'>
>>> (x+10 for x in range(1,10)) 
<generator object <genexpr> at 0x7f1935b315e8>

For/else

>>> for x in [1,2,3]:
...     x
... else:
...     print("fin!")
... 
1
2
3
fin!
>>> for x in [1,2,3]:
...   if x >= 3:
...     break
...   else:
...     x
... else:
...   print("fin!")
... 
1
2

Clases

  • en python2 se usa lo que se llama nueva clase:
    >>> class Pepito1():
    ...     pass
    ... 
    >>> dir(Pepito1())
    ['__doc__', '__module__']
    >>> class Pepito2(object):
    ...     pass
    ... 
    >>> dir(Pepito2())
    ['__class__', '__delattr__', '__dict__', '__doc__', '__format__', 
     '__getattribute__', '__hash__', '__init__', '__module__', '__new__', 
     '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', 
     '__str__', '__subclasshook__', '__weakref__']
    
  • en python 3 son todos del tipo "nuevo"
  • si al definir un metodo, se te olvida poner self, usara el primero como self

inicializacion de instancias

  • si se define en la clase, son atributos "compartidos"
    • en caso de ser mutables, podria generarse el patron Borg en el que se comparte el estado entre varios
  • en el init solo se especifican atributos propios de la instancia

multiherencia

>>> class Pepito3 (Pepito2, dict):
...    pass
>>> dir(Pepito3())
['__class__', '__cmp__', ... '__weakref__', 'clear', 'copy', 'fromkeys', 'get',
 'has_key', 'items', 'iteritems', 'iterkeys', 'itervalues', 'keys', 'pop',
 'popitem', 'setdefault', 'update', 'values', 'viewitems', 'viewkeys',
 'viewvalues']
  • Para llamar a papá
    super(clase, instancia).metodo
    
  • MRO (Method Resolution Order)

Excepciones

  • las excepciones en python son baratas, se recomienda usarlas
  • se específico
  • finally ejecutara siempre
  • else solo ejecuta si no salto la excepcion

Decoradores

Descripcion

  • Es una funcion que devuelve una funcion
  • Pone codigo alrededor de otras funciones: las decora
  • Puede contener parametros, pero se complica la cosa

Uso

# fichero: gigas_api/api/handlers/virtualmachine.py
from api.handlers.base import admin_only

class K(object):
    @admin_only
    def post(self, virtual_machine_id):
        resp = vm_actions.unlock(self.console, self.user_id, self.cloud_id, 
                                 {"id": virtual_machine_id}, self.is_admin,
                                 vm_mng_cls=self.vm_mng_cls)
        self.write_response(resp['code'], resp['response'])

Creacion

def admin_only(func):
    """
    decorator to check if a method is called as admin
    """
    def _decorator(self, *args, **kwargs):
        # access a from TestSample
        if not getattr(self, "is_admin", False):
            logging.error("tried to access an admin only method")
            raise HTTPError(403, "Insufficient privileges")
        func(self, *args, **kwargs)
    return _decorator

Generadores

Iteradores

  • Se recorren una sola vez
  • no hacen una copia de toda la informacion
  • comodos para recorrerlo en un for
  • terminan con un stop iteration
  • itertools

Ejemplo

>>> from managers.db_manager import DiskManager
>>> DiskManager(1,1,True).get_list()
<managers.db_manager.ListIterator object at 0x7f85c8b91a10>
>>> it = DiskManager(1,1,True).get_list()
>>> it.next()
{
  "created_at": "2014-01-28T12:36:06",
  "id": 1579,
  ....
}
>>> it.next()
{
  "created_at": "2014-01-28T12:36:06",
  "id": 1580,
  ....
}
>>> for i in it:
...    i.id
# una lista muy larga
2284L
2285L # y termina
>>> it.next() #no se puede volver atras
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "managers/db_manager.py", line 27, in next
    return self._get_next()
  File "managers/db_manager.py", line 53, in _get_next
    raise StopIteration
StopIteration

Generadores

  • se parecen a los iteradores, pero no parten de ninguna coleccion, sino que la generan
  • yield
>>> def counter():
...   x = 0
...   while True:
...     x += 1
...     yield x
>>> counter()
<generator object counter at 0x7f85c75c2370>
>>> a = counter()
>>> next(a)
1
>>> next(a)
2
>>> next(a)
3
>>> a = counter()
>>> next(a)
1

Sintaxis util

  • unpack
  • x if y else z

Pythonic

Ducktyping

  • muchos objetos presentan interfaces parecidas
  • puede darte igual si te dan una lista/tupla por ejemplo
  • Se suele decir que:

Si anda como un pato

Tiene el color de un pato y

Hace -Cuack-

Me da igual lo que sea: lo trataré como a un pato

Truthy

Muchas cosas evaluan a True/False por lo que en determinados casos puede hacerse:

if x:
    foo(x)

Cumpliendo con 80 caracteres

  • Para poder mantener el tamaño, se pueden usar parentesis para que python no evalue
  • Los strings pueden ademas continuarse sin concatenar
# fichero: retoken/retoken.py
self.logging.error("Couldn't connect to redis: "
                   "there is no connection info")

Docstring

Entorno y herramientas

setup.py

  • configuracion de un paquete
  • tiene comandos para gestionarlos de cara a un mantenedor

pip

  • gestor de paquetes
  • install
  • uninstall
  • freeze

virtualenv

  • entorno virtual de python
  • version especifica
  • tira de pip y pipy
  • (casi) independiente del sistema
  • source/deactivate

virtualenvwrapper

  • set de herramientas sobre virtualenv
  • facilidad de reutilizacion
  • mkvirtualenv
  • workon

nose

  • test finder
  • provee algunas comodidades en nose.tools
    • ok_
    • eq_
    • raises

tox

virtualenv + nose = tox

Librerias

core

  • collections
  • itertools
  • functools
  • abc

externas

  • requests
  • tornado
  • flask
  • django
  • redis

Recursos

  • Mejores formas de escribir python:

https://gist.github.com/kracekumar/09a60ec75a4de19b346e

  • ebook: Writing idiomatic Python

https://www.jeffknupp.com/writing-idiomatic-python-ebook/