

=================
 Python avanzado
=================

:Autor: Alberto Bertogli (albertito@gmail.com)
:Fecha: Sábado 7/Octubre/2006

.. footer:: Día de lenguajes · 7/Oct/2006


El plan!
========

- Mostrar los elementos avanzados del lenguaje.
- Concentrarnos principalmente en su uso, no en sus mañas.
- Ver las cosas locas que se pueden hacer, y la magia que hay detrás.
- ¿Porque?
    - A todos les gustan las cosas locas.
    - Las fieras en su hábitat: control de complejidad.
    - Incrementar la calidad del código.


¿Como?
======

- Agregados sintácticos:
    - Operadores básicos.
    - Listas por comprensión.
    - Decorators.
- Propiedades mágicas del lenguaje:
    - Introspección
    - Métodos especiales.
    - Interfaz de iteración.
    - Generators.
    - with statement.
    - Metaclases.
- Mucha imaginación.


Operadores básicos I
====================

- Por si no lo vieron a la mañana.
- Todos los métodos mágicos se nombran de la forma *__metodo__*.
- Las operaciones básicas se pueden sobrecargar:
    - \+ \- \* / // \*\* %
    - ^ \| & << >> ~
    - Equivalentes in-place: \+= \-= ...
    - Igualdades y desigualdades varias
- Nos permiten proveer sintaxis amistosa y legible para nuestros objetos.


Operadores básicos II
=====================

- Podemos abusarnos de la sintaxis clara.
- Tener cuidado de no dar sorpresas.
- Ejemplos:
    - Se usan mucho en las clases built-in.
    - Si extrañamos C++: **<<** y **>>** para I/O.
    - **\|** para paso de mensajes entre objetos onda Erlang.


Listas por comprensión
======================

- Símil a expresar conjuntos por comprensión
- Ejemplos::

    [ x + 1 for x in l ]
    [ (x, y) for x in l1 for y in l2 ]
    [ f(x) for x in l]  ==  map(f, l)
    [ x for x in l if f(x) ]  ==  filter(f, l)
    [ f(x, y) for x in l1 for y in l2 if p1(x) and p2(x) ]


Introspección I: Mirándose el ombligo
=====================================

- Es poder obtener información en tiempo de ejecución acerca de los objetos.
- Ejemplo clásico: preguntar por los parámetros de una función, la lista de
  atributos de un objeto, a que clase pertenece, etc.
- Muy útil para aprender y debuggear.
- Mas útil aún para meter mano de forma combinada con las otras cosas que
  vamos a ver.
- Módulo inspect


Introspección II: Un montón de espejos
======================================

- Ejemplos simples::

    dir(thread) => [... 'stack_size', 'start_new',
                    'start_new_thread' ... ]
    isinstance(1, int) => True
    f.func_code.co_argcount => Cant. de args de f

- Ejemplos clásicos:
    - Módulo pickle
    - Serialización de objetos para RPC
- Ejemplos mas divertidos:
    - Módulo traceback
    - Módulo dis


Métodos especiales I
====================

- Gran parte de la sintaxis normal termina en la invocación de métodos
  especiales.
- Son como los operadores, solo que reflejan la sintaxis.
- Los mas simples (usados para tipos onda *containers*):
    - **getitem**, **setitem** y **delitem** para *obj[key]* (*key* puede ser
      un objeto cualquiera, con sintaxis para slices).
    - **__contains__** para *if key in obj*.


Métodos especiales II
=====================

Emulando funciones
------------------

- La invocación es también un método!
- *f(x)  ==  f.__call__(x)*
- Nos permite armar objetos que se puedan llamar como una función.
- Podemos armar "wrappers" a funciones.
- Ejemplo interesante: aplicación parcial (*functools.partial*)


Métodos especiales III (a)
==========================

Acceso a atributos I
--------------------

- El acceso a los atributos también se hace a través de métodos.
- El camino es un poco mas largo que con la ejecución de funciones, y no es el
  mismo para el get, set y delete.
- Dibujin de get en la otra filmina.
- Símil para set y del.


Métodos especiales III (b)
==========================

Acceso a atributos II
---------------------

.. image:: attraccess.png


Métodos especiales III (c)
==========================

Acceso a atributos III
----------------------

- No es tan engorroso como parece, y solo lo usamos para cosas locas.
- Ejemplos built-in:
    - Descriptors con property().
    - staticmethod y classmethod (mas adelante).
- Ejemplos:
    - Loguear todos los accesos a los métodos para debugging.
    - Restringir acceso a instancias de ciertas clases.
    - RPC transparente.


Interfaz de iteración
=====================

- Hay magia detrás del *for i in obj*.
- Primero se le pide a *obj* que devuelva un *"objeto iterador"* usando el
  atributo *__iter__()*.
- Después se va llamando al método *next()* del iterador.
- Cuando no quedan mas items, se levanta una excepción *StopIteration* y el
  *for* termina de iterar.


Generators I
============

- Se lo robamos a Ricky (aunque el les dice iterators).
- La idea es la misma, tiramos cosas con *yield* hasta que cuando se agota
  levantamos *StopIteration* (o sale sola con *return*).
- "Encajan" en la interfaz de iteración de forma natural
- Generator expressions: *( (x, t(x)) for x in l if p(x) )*
- Podemos "pasarle" cosas al generator con *.send()* y mandarle excepciones
  con *.throw()*
- Ejemplos aparte


Decorators I: ¿Que son?
=======================

- Un decorator es una función normal.
- Toma una función como parámetro, devuelve una función.

- Se usa así::

    def f(x):
        return x + 1
    f = decorate(f)

- Horrible, demasiado explicito, poco practico, difícil de leer.


Decorators II: Belleza
======================

- Sintaxis linda para lo anterior::

    @decorate
    def f(x):
        return x + 1

- Podemos apilarlos y pasarle parámetros (ojo con la evaluación)::

    @debug
    @dtag('minor')
    def f(...): ...

- ¿Pero de que nos sirven?


Decorators III: Aplicación
==========================

- Son **muy** útiles.
- Nos permiten todo tipo de triquiñuelas con una sintaxis agradable,
  combinando las otras cosas que vimos.
- Algunos ejemplos clásicos:
    - staticmethod y classmethod (built-in).
    - Logueo y tracing de ejecución.
    - Checkeo de permisos de ejecución.
- Algunos ejemplos apenas mas originales:
    - Ejecución condicional.
    - Ejecución asincronica con paso de mensajes.
    - Funciones lazy y "onda dataflow".


with statement
==============

- Nuevo en Python 2.5
- Permite cosas como::

    with db.transaction() as trans:
        ...

- Llama a *__enter__()* al entrar y a *__exit__()* al salir
- Útil para transacciones, locks, y bloques donde se quiera efectuar un
  conjunto de acciones con algún objeto que deba ser notificado.


Metaclases
==========

- No vamos a llegar con tiempo para esto.
- El 99% de los programadores de Python no lo usa nunca (de forma consciente).
- Son las clases de las clases. Sirven para tener control acerca de como se
  crea una **clase**, y manipularla.
- Ejemplos de uso simples:
    - Registrar una clase en un diccionario común.
    - Modificar los métodos y atributos.
- Ejemplos de uso avanzados
    - SQLObject y SQLAlchemy


Chau
====

.. class:: huge

   *¡Fin!*

¿Que sigue? ¡La noche de los museos!

