[Python] Funzioni come moduli

Daniele Varrazzo piro a develer.com
Mar 1 Lug 2008 01:45:06 CEST


Leonardo ha scritto:
>> Mi sembra di capire che tu fai execfile per sfruttare gli effetti secondari
>> delle istruzioni eseguite. Se posso, ti suggerisco di creare dei moduli
>> plugin che definiscano unicamente una funzione. Puoi "caricare" tutti i
>> plugin all'avvio del programma o ad un certo evento e poi usare le funzioni
>> dove servono.
>>
>> Puoi definire ad esempio che ogni plugin debba esportare una funzione
>> handle_<qualcosa> con una signature prefissata - diciamo (self,
>> server_response). All'atto di caricare i plugin puoi fare (untested, e
>> senza error handling):
>>
>>     env = {}
>>     execfile(my_file, env)
>>     
>>     for k, v in env.iteritems():
>>         if k.startswith('handle_'):
>>             register_plugin(v)
>>             break
>>     else:
>>         complain("no plugin in this file")
> 
> Non ho ben capito.
> Scusate la mia niubbagine, ma sono da pochi mesu su python ed è il primo
> linguaggio che "studio".

Figurati :) ma se sei all'inizio col linguaggio non partire subito col provare 
a fare cose semi-magiche: vedi se puoi cavartela usando i moduli in maniera 
per così dire statica.

> Mi stai dicendo di creare un'unica funzione all'interno di ogni modulo e
> importare tutti i moduli all'avvio, dopodichè chiamare la funzione
> anzichè il modulo? 

Sì... anche perché non si "chiama" un modulo (cattiva educazione?). Quello che 
vedi sono gli effetti collaterali della sua esecuzione, che come fai tu sono 
abbastanza fuori controllo (con i rischi che Sandro ha citato in queste mail).

> e cosa dovrei passare all'argomento self della
> funzione? Un'istanza di Rule?

Un istanza di un oggetto adatto ad essere maneggiato da un plugin. Immagino 
che tu abbia lo stato del sistema IRC con cui vuoi interagire (non so, oggetti 
tipo la connessione, il server, la stanza) con metodi che consentano 
l'osservazione ("Stanza.get_partecipanti()") o l'interazione 
("Utente.kick()")... non conosco bene IRC, non ho mai pensato a che 
oggetti/metodi ci vorrebbero. Allora un plugin sarebbe una funzione che prende 
in input un modello di questo genere e lo manipola come deve:

     def handle_kick_all_the_bastards(world):
         for stanza in world:
             tutti = stanza.get_partecipanti()
             tutti.sort(key=attrgetter('bastardaggine'), reverse=True)
             tutti[0].kick()

> Andrei in perdita dal punto di vista delle prestazioni facendo così?

No: self non è una variabile speciale, non cambia niente ad interagire col 
proprio stato o con lo stato altrui. E comunque non è questo il momento di 
preoccuparsi di prestazioni: prima si fa qualcosa che funziona e poi, se è 
lenta, si misura dove e la si ottimizza dove serve.

>> Se i plugin hanno la possibilita' di poter intervenire in diverse fasi del
>> tuo processo, potresti definire una classe BasePlugin fornita dei diversi
>> hook e implementare gli hook desiderati in ogni plugin.
> Questa frase non l'ho capita proprio del tutto..

Il problema di una funzione handle come quella di sopra è che la si può solo 
eseguire ad un comando esterno (es. l'amministratore preme il tasto "Prendi a 
calci tutti", oppure ogni giorno alle 15.00), non si può far scattare 
automaticamente all'avverarsi di una certa condizione (es. quando un utente si 
connette, quando qualcuno dice "apriti sesamo"...): per fare questo il plugin 
dovrebbe essere dotato di tanti handle che il sistema possa chiamare al 
momento giusto:

     class Plugin:
         def __init__(world):
             self.world = world

         def on_connect(self, user):
             pass

         def on_message(self, user, string):
             pass

i tuoi plugin sarebbero sottoclassi che reagiscono a certi metodi e 
implementano i comportamenti per cui sono progettati:

     class Salutatore(Plugin):
         def on_connect(self, user):
             user.send("Ciao, " + user.name)

     class PortaSegreta(Plugin):
         def on_message(self, user, string):
             if "apriti sesamo" in string:
                 self.world.create_room("grotta")
                 for i in range(40):
                     self.world.create_bot("Ladrone")

Sono i pattern Strategy e Template Method che lavorano insieme.

(Per una bella introduzione sui design pattern in Python, ci sono i due talk 
di Alex Martelli del PyCon Uno: slide e materiale sono disponibili a 
http://www.develer.com/website/it/video-pycon-2007)

Ciao!

-- 
Daniele Varrazzo - Develer S.r.l.
http://www.develer.com


Maggiori informazioni sulla lista Python