[Python] Metodi decorati con classi

Marco Giusti marco.giusti a gmail.com
Lun 22 Apr 2013 15:40:41 CEST


On Mon, Apr 22, 2013 at 02:52:34PM +0200, Pietro Battiston wrote:
> Il giorno lun, 22/04/2013 alle 13.53 +0200, Pietro Battiston ha scritto:
> > Il giorno lun, 22/04/2013 alle 10.27 +0200, Marco Giusti ha scritto:
> > > On Mon, Apr 22, 2013 at 08:58:39AM +0200, Pietro Battiston wrote:
> > > [...]
> > > >[...] 
> > > > 
> > > > Il mio problema è semplicemente che i due
> > > >     print "self is", self
> > > > stampano due cose diverse.
> > > 
> > > normale perché sono due cose diverse: [...]. Forse è per questo che non si vede spesso oggetti usati
> > > come decoratori.
> > > 
> > > A questo punto mi chiedo l'utilità di avere una classe come decoratore.
> > > Incapsulazione? Ereditarietà?
> > 
> > 
> > [...]
> > 
> > Alla luce del tuo chiarimento però mi è chiaro che questo modo di
> > operare è _meno_ potente...
> 
> Ritratto:
> http://www.outofwhatbox.com/blog/2010/07/python-decorating-with-class/
> 
> Sostanzialmente la soluzione è aggiungere alla classe decoratore il
> metodo
> 
>     def __get__(self, obj, ownerClass=None):
>         # Return a wrapper that binds self as a method of obj (!)
>         return types.MethodType(self, obj)
> 
> e aspettarsi in __call__ il "self" dell'altra classe come secondo
> argomento:
> 
>     def __call__(self, otherself, *args):
>         print "self is", self
>         print "otherself is", otherself
>         print "args are", args
>         print "inside myDecoratorC.__call__()"
> 
> 
> Ho provato. Funziona. Con calma finirò anche per capire perché...

forse ti complichi un po' la vita ma sicuramente la complicherai a chi
verrà dopo di te. un antico proverbio cinese dice: "non scrivere mai
codice che non vorresti mantenere quando scritto da altri".

il codice funziona, ed è corretto, perché stai definendo un tipo
descrittore, pratica quando hai una situazione del genere: `a.x`, di
fatto ottieni un `x.__get__(a)` e quindi considerando il decoratore:

	class Dec(object):
		def __init__(self, f):
			self.f = f
		def __get__(self, instance, owner=None):
			return types.MethodType(self, obj)
		def __call__(self, other_self, *args, **kwds):
			pass

	class Spam(object):
		@Dec
		def foo(self):
			pass

	Spam().foo()

dovrebbe diventare:

	s = Spam() # nessun problema
	func = s.foo # foo.__get__(s, type(s))
	func() # che è Dec.__call__

ma i descrittori sono una cosa bruttina, imho, e con casi particolari:
owner può non essere passato e instance può essere None.

ciao
m.


Maggiori informazioni sulla lista Python