[Python] Funzioni come moduli

Daniele Varrazzo piro a develer.com
Mar 1 Lug 2008 00:49:02 CEST


Alessandro Dentella ha scritto:
>> A me non sembra che il global namespace del chiamante venga inquinato:
>>
>>     In [1]: ENV = {}
>>
>>     In [2]: execfile('plugin_A.py', ENV)
>>
>>     In [3]: a = ENV['A']()
>>
>>     In [4]: a.test()
>>     [ ...roba... ]
>>
>>     In [5]: sys
>>    
>> ---------------------------------------------------------------------------
>>     <type 'exceptions.NameError'>             Traceback (most recent call
>> last)
>>
>>     /home/piro/py/<ipython console> in <module>()
>>
>>     <type 'exceptions.NameError'>: name 'sys' is not defined
> 
> 
> mi arrendo... il che mostra che non ho compreso bene il significato di
> questo dizionario e tantomeno comprendo cosa succeda in realtà  se uso due
> dizionari (globals, locals) e se ne uso uno soltanto...
> 
> Questo utilizzo è quindi completamente equivalente ad un import?

:) questa discussione l'ho già vissuta meno di un mese fa in una ML di amici 
smanettoni...

Puoi ottenere lo stesso scopo: esecuzione dinamica del codice, ma gli 
strumenti non sono equivalenti.

__import__ ha una semantica _perfettamente documentata_, ma che a leggerla 
senza pensare al contesto a cui serve sembra assurda. Per esempio che 
__import__('foo.bar.baz') restituisce foo ma come effetto collaterale carica 
bar e baz. Come anche il significato criptico dei parametri.

In realtà __import__ è solo l'hook implementativo dello statement import, e la 
sua semantica è quella dello statement. E' esposta solo per permettere 
(immagino rimpiazzandola ma non lo so) gli hook ad import time. Porta con sé 
tutti gli effetti dell'import, che nel contesto di scrivere un sistema di 
plugin sono scomodi: per esempio devi avere la directory contenitore nel 
pythonpath, o che __import__() non ricarica i moduli, ma devi usare reload() 
(che non è ricorsiva e fare ereditarietà tra i plugin diventa ancora più 
delicato). Tutti problemi superabili, ma che fanno capire che non è questo lo 
scopo per cui la funzione è progettata.

La funzione execfile() è esposta all'API pubblica (le funzioni __così__ lo 
sono, ma sono progettate allo scopo di essere usate in maniera peculiare dal 
linguaggio) e la sua semantica è esplicita: tu crei un namespace, chiedi di 
eseguire il contenuto di un modulo in quel contesto e, dopo l'esecuzione, hai 
a disposizione il namespace con il contenuto modificato (nuovi oggetti o stato 
alterato). Mi sembra adeguato allo scopo di creare plugin, no?

Poi __import__ ha il suo bello (Valentino Volonghi ha citato la funzione 
namedAny() di Twisted, che la usa per importare dinamicamente qualunque 
oggetto dai moduli), ma se ho a disposizione due funzioni: una pubblica, con 
la semantica adatta al mio scopo e una, progettata per altri scopi, che con 
gli aggiustamenti giusti può fare al caso mio, allora in mancanza di altri 
problemi preferisco usare la prima.

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


Maggiori informazioni sulla lista Python