13.01.2015 Views

Booklet A4/A5 - PET: Python Entre Todos - Python Argentina

Booklet A4/A5 - PET: Python Entre Todos - Python Argentina

Booklet A4/A5 - PET: Python Entre Todos - Python Argentina

SHOW MORE
SHOW LESS

Create successful ePaper yourself

Turn your PDF publications into a flip-book with our unique Google optimized e-Paper software.

Funciones decoradoras sin argumentos 49<br />

b. Con argumentos.<br />

2. Clases decoradoras<br />

a. Sin argumentos.<br />

b. Con argumentos.<br />

La llamada del callable en un decorador debe ser explícita, un decorador podría por<br />

ejemplo hacer que no se ejecute la función decorada.<br />

Ejemplo:<br />

def disable(callable):<br />

"""Decorates callable and prevents executing it."""<br />

def wrap(*args, **kwargs):<br />

logging.debug("{0} called but its execution "\<br />

"has been prevented".format(<br />

callable.__name__)<br />

)<br />

return wrap<br />

@disable<br />

def yes(string='y', end='\n'):<br />

[...]<br />

Funciones decoradoras sin argumentos<br />

En una función decoradora que no recibe argumentos su primer y único parámetro es<br />

el callable decorado en cuestión. Ya en la función anidada es dónde se reciben los<br />

argumentos posicionales y de palabra clave que se utilizaron para llamar al callable<br />

decorado.<br />

Esto puede verse en cualquiera de los decoradores mostrados anteriormente.<br />

Funciones decoradoras con argumentos<br />

Veremos ahora un ejemplo de función decoradora que recibe argumentos propios.<br />

Vamos a trabajar en un equivalente de log_callable que permita especificar si queremos<br />

contar o no el número de llamadas.<br />

<strong>Python</strong> <strong>Entre</strong> <strong>Todos</strong> (número 1, Agosto 2010) — http://revista.python.org.ar<br />

20 Concurrencia Indolora: el módulo multiprocessing<br />

# Esperamos un ratito, o hasta que termine el hilo,<br />

# lo que sea más corto.<br />

hilo.join(.3)<br />

print "Termina el programa"<br />

# Importante: los módulos no deberían ejecutar<br />

# código al ser importados<br />

if __name__ == '__main__':<br />

main()<br />

Sí, lo único que cambia es import threading por import multiprocessing y<br />

Process en vez de Thread. Ahora la función trabajador se ejecuta en un intérprete<br />

python separado. Como son procesos separados, usa tantos cores como procesos<br />

tengas, haciendo que el programa pueda ser mucho más rápido en una máquina<br />

moderna.<br />

Antes mencioné deadlocks. Tal vez creas que tener un poco de cuidado y poner locks<br />

alrededor de variables te evita esos problemas. Bueno, no. Veamos dos funciones f1 y<br />

f2 que necesitan usar dos variables x y y protegidas por locks lockx y locky:<br />

# -*- coding: utf-8 -*-<br />

import threading<br />

import time<br />

x = 4<br />

y = 6<br />

lock_x = threading.Lock()<br />

lock_y = threading.Lock()<br />

def f1():<br />

lock_x.acquire()<br />

time.sleep(2)<br />

lock_y.acquire()<br />

time.sleep(2)<br />

lock_x.release()<br />

lock_y.release()<br />

def f2():<br />

lock_y.acquire()<br />

time.sleep(2)<br />

<strong>Python</strong> <strong>Entre</strong> <strong>Todos</strong> (número 1, Agosto 2010) — http://revista.python.org.ar

Hooray! Your file is uploaded and ready to be published.

Saved successfully!

Ooh no, something went wrong!