Bag dinamiche e Resolver¶
Introduzione¶
Una bag oltre a valori scalari, vettoriali ed altre bag può contenere un oggetto dinamico che si chiama resolver ovvero un qualsiasi oggetto che erediti dalla classe BagResolver
.
Un resolver è un oggetto dinamico che restituisce il risultato di una chiamata a funzione come se fosse un valore realmente contenuto nella bag.
Quando una bag contiene o è costituita da elementi dinamici viene anche definita Bag dinamica. Possiamo avere Bag dinamiche che contengono
chiamate a query su un database
chiamate a webservice
chiamate a funzioni che calcolano valori in tempo reale
chiamate al sistema operativo
O qualunque altra cosa vi possa venire in mente quando definite un resolver
BagResolver¶
L’idea del resolver è quella di nascondere le chiamate esplicite, definendo invece un oggetto che le esegue quando si accede ad un path della bag e che ne restituisce il risultato come se fosse un valore statico, in modo del tutto trasparente.
Un resolver fa l’override della primitiva __call__
ed implementa il metodo load() e quando si accede ad un elemento resolver viene invocato.
Un resolver però può avere anche una cache, utile specialmente se la chiamata è lenta o onerosa.
Se si imposta il parametro cacheTime viene salvata localmente all’indirizzo del resolvere il risultato dell’ultima chiamata e questo viene restituito a tutti gli accessi successivi finché non scade il tempo di cache.
Il valore di default del cacheTime è 0.
Un resolver deve implementare il metodo load()
Esempio 1: TimeResolver¶
Un esempio molto semplice di resolvere è il TimeResolver
from datetime import datetime from gnr.core.gnrbag import Bag, BagResolver class TimeResolver(BagResolver): def __call__(self): return datetime.now()
Ora proviamo ad usarlo
>>> mybag = Bag()
>>> mybag['now'] = TimeResolver()
>>> print mybag['now']
2010-11-18 11:47:13.237443
Se impostiamo un cacheTime pari a 100. Il valore verrà aggiornato solo ogni 100ms.
>>> ct=100
>>> mybag['now']=TimeResolver(cacheTime=ct)
>>> print mybag['now']
2010-11-18 11:49:34.257631
Esempio 2: UserInfoResolver¶
In questo resolver il risultato è una Bag contenente alcune informazioni prese da dalle librerie os e socket ( hostname, IP, PID, user).
from gnr.core.gnrbag import Bag, BagResolver import socket, os class UserInfoResolver(BagResolver): def load(self): result = Bag() try: result['hostname']=socket.gethostname() result['ip']=socket.gethostbyname(result['hostname']) except: result['hostname']='localhost' result['ip']='unknown' result['pid']=os.getpid() result['user']=os.getenv('USER') result['ID']=result['ip']+'-'+str(result['pid'])+'-'+result['user'] return result
Vediamo il resolver all’opera.
>>> mybag = Bag()
>>> mybag['info'] = UserInfoResolver()
>>> info = mybag['info']
>>> template = "This is the process %s.\nYou are user %s, from the host %s at the address %s"
>>> print template %(mybag['info.pid'], mybag['info.user'], mybag['info.hostname'], mybag['info.ip'])
Esempio 3: RssFeedResolver¶
Questo resolver riceve l’URL di un RSS feed e, dal momento che si popola facilmente una bag a partire da un XML è molto semplice gestire il risultato.
class RssFeedResolver(BagResolver): def init(self, feed): self.feed=feed def load(self): feed= Bag(self.feed)['rss.channel'] result= Bag() result['title']= feed.pop('title') result['description']= feed.pop('description') result['link']= feed.pop('link') result['language']= feed.pop('language') result['copyright']= feed.pop('copyright') dig= feed.digest('#v.title, #v.description, #v.pubDate, #v.link') news=Bag() for title, description, pubDate, link in dig: news.setItem(title.replace('.', '\.').replace(' ','_'),description,link=link, date=pubDate, title=title) result['news']=news return result
Ecco come funziona il resolver:
>>> mybag['feeds.washingtonpost']= RssFeedResolver('http://www.washingtonpost.com/wp-dyn/rss/world/index.xml')
La Bag risultante è strutturata come segue:
item |
value |
---|---|
title |
washingtonpost.com - World News and Analysis From The Washington Post |
description |
World news headlines from the Washington Post,including international news and opinion from Africa, North/South America,Asia,Europe and Middle East. Features include world weather, news in Spanish, interactive maps, daily Yomiuri and Iraq coverage. |
link |
http://www.washingtonpost.com/wp-dyn/content/world/index.html?nav=rss_world |
language |
EN-US |
copyright |
None |
news |
Bag of News |
Ogni item è un BagNode strutturato come segue:
label |
value |
attributes |
---|---|---|
In_Russia,_A_Secretive_Force_Widens_ |
MOSCOW - On Nov. 15, the Russian Interior Ministry and Gazprom, the state-controlled energy giant, announced… |
link, date, title |
Scorciatoia: il BagCbResolver¶
In realtà se il risultato che deve essere ritornato è una semplice chiamata a funzione si può evitare di definire una classe Resolver apposta.
E si può usare una istanza del più generico BagCbResolver
che è un BagResolver che chiama una funzione callback passata come parametro.
>>> from gnr.core.gnrbag import Bag, BagCbResolver >>> from datetime import datetime >>> mybag = Bag() >>> mybag['now'] = BagCbResolver(datetime.now) >>> print mybag['now']2010-11-18 14:23:40.070095
Questa scorciatoia funziona con tutte le funzioni callback.
- def sayHello():
return “Hello World!”
>>> mybag['hello'] = BagCbResolver(sayHello) >>> print mybag['hello'] Hello World!
In alternativa si può usare il metodo setCallBackItem
>>> mybag.setCallBackItem('hello', sayHello) >>> print mybag['hello']Hello World!
Autore della sezione: Giovanni Porcari