Lawrence

Twist again
posts - 73, comments - 168, trackbacks - 37

venerdì 9 gennaio 2009

IronPython In Action, protocolli, metaprogrammazione e altro

Il capitolo 8 si butta in profondità sui concetti di protocollo, metaprogrammazione e spiega l’interfacciamento di IronPython con .NET nei casi meno ovvi.

I post precedenti sono: testing, proprietà, dialog e Visual Studio, first class functions e xml, applicazioni e design pattern, oggetti .NET e IronPython, introduzione a Python, introduzione al libro e il preambolo.

Personalmente direi che arrivati al capitolo 8 (approfondendo con la documentazione di Python) si possiede una buona base per essere autonomi.

I protocolli, comunque, sono interfacce soft che funzionano tramite il duck typing senza alcun tipo di forzatura a compile time.

Esistono dei pacchetti, come zope.interface, che aiutano a formalizzare le cose nel caso di un sistema a componenti.

Personalmente mi era sfuggito ma l’autore fa notare come esista almeno un caso di duck typing in C#, attraverso il funzionamento dell’interfaccia IEnumerable e il foreach.

Ci sono tonnellate di esempi in Python sul funzionamento dei protocolli (dopotutto sono uno dei concetti fondamentali), tipo la determinazione della lunghezza di un contenitore:

>>> lst = [1, 2, 3, 4]
>>> d = {1: 'a', 'b': 'c'}
>>> class Container(object):
...     def __len__(self):
...         return 3
... 
>>> len(lst)
4
>>> len(d)
2
>>> len(Container())
3

La classe custom Container si adatta al protocollo __len__ proprio tramite duck typing.

Ad esempio esistono anche __str__ (chiamato da str(), %s e print) per la rappresentazione in stringa di un oggetto oppure __nonzero__ per determinare il valore booleano di verità di un oggetto.

Python supporta anche l’overloading degli operatori, implementato anch’esso tramite protocolli:

>>> class Three(object): 
...     def __add__(self, other):
...         return other + 3 
... 
>>> t = Three() 
>>> t + 2 
5

__add__ è soltanto uno dei tanti metodi speciali per implementare l’overloading, altri sono: __sub__, __div__, __mul__, __or__ ecc. ecc.

Per restare in tema anche il concetto di iterazione che la generazione sono protocolli. Il generator protocol usa l’espressione yield valore per sospendere l’esecuzione di una funzione, salvarne lo stato e permettere la ripresa dal punto di salvataggio.

Grazie alla possibilità di inviare valori o lanciare eccezioni all’interno di un generatore è possibile implementare delle coroutine anche in Python. Questo apre la porta a concetti come il green threading (thread in user space) o i thread cooperativi senza pre-emption.

Sempre grazie al concetto di protocollo è possibile customizzare l’accesso agli attributi di un oggetto usando metodi speciali come __getattr__, __setattr__, __delattr__ e le funzioni hasattr(), getattr(), setattr(), delattr(). Tra l’altro gli attributi (metodi compresi) sono memorizzati in un attributo speciale chiamato __dict__.

Una volta introdotto e spiegato il concetto di protocollo si passa alla metaprogrammazione avanzando la parola metaclasse.

Le metaclasse non sono altro che il tipo delle classi. Le classi in Python sono oggetti normalissimi come gli altri, quindi hanno un tipo, il loro tipo è la loro metaclasse.

La metaclasse di default in Python è type:

>>> type(type) is type
True

Usando l’attributo __metaclass__ è possibile modificare il comportamento di default:

>>> class PointlessMetaclass(type):
...     def __new__(meta, name, bases, classDict):
...         return type.__new__(meta, name, bases, classDict)
... 
>>> class SomeClass(object): 
...     __metaclass__ = PointlessMetaclass

Lo scopo delle metaclassi è semplice: introdurre modifiche prima dell’istanziazione di una classe. Non sono tremendamente usate in Python (per fortuna), ma sono utili per registrazioni di classi, creazione di DSL, ispezioni di classi, decorazioni, mixin e altro ancora.

Il libro a questo punto mostra un estensivo esempio di profiling di una classe attraverso una metaclasse che decora tutti i suoi metodi misurandone il tempo di esecuzione.

Dettagli a parte (per cui rimando al libro) il capitolo si conclude con una serie di differenze tra IronPython e la CLR per far capire come si affrontano in IronPython le cose che non hanno un corrispettivo chiaro.

Menziona: array .NET, generics, overloading di metodi esplicito, out, ref, params, puntatori, value e reference types, chiamata di metodi di una interfaccia, attributi .NET (che non sono supportati direttamente se non tramite classi stub).

Conclude mostrando come creare assembly usando la compilazione statica (anche a runtime) attraverso il metodo clr.CompileModules.

Il capitolo 8 è la fine della seconda parte del libro. La terza parte si butta sulle parti avanzate di .NET e il loro uso da IronPython (.NET 3, SilverLight, ASP.NET e altro ancora).

posted @ lunedì 1 gennaio 0001 00:00 | Feedback (1) | Filed Under [ ironpython ]

Powered by:
Powered By Subtext Powered By ASP.NET