Decorators using instance variables

castironpi castironpi at
Fri Aug 22 05:49:12 CEST 2008

On Aug 21, 9:22 pm, robert2821 <robert2... at> wrote:
> Hi,
> I'm new; greetings all!
> I'm wondering if the following program should work.  I think it should
> print 'Hello, World', but instead it produces a TypeError.  Is this a
> bug in decorators, a feature of them, or a mistake or misunderstanding
> on my part?
> TIA,  Bob
> def    getdec (f):
>     dec = decorator (f)
>     return dec. docall
> class    decorator:
>     def __init__ (self, f):
>         self. f = f
>     def docall (self, *a):
>         return self. f (*a)
> class    test:
>     @ getdec
>     def doit (self, message):
>         print message
> if __name__ == '__main__':
>     foo = test ()
>     foo. doit ('Hello, world')
> < 1KViewDownload

Have a look at this and fiddle with it:

from types import MethodType
class    decorator(object):

	def __init__ (self, f):
		self. f = f

	def docall (self, *a):
		print a
		return self. f (*a)

	def __get__( self, instance, owner ):
		print 'in __get__', instance, owner
		if instance is not None:
			return MethodType( self.docall, instance )
		return self.f

class    test:
	@ decorator
	def doit (self, message):
		print message

if __name__ == '__main__':
	foo = test ()
	print test.doit
	print foo.doit
	foo. doit ('Hello, world')


in __get__ None __main__.test
<function doit at 0x00A01170>
in __get__ <__main__.test instance at 0x009FEE18> __main__.test
<bound method ?.docall of <__main__.test instance at 0x009FEE18>>
in __get__ <__main__.test instance at 0x009FEE18> __main__.test
(<__main__.test instance at 0x009FEE18>, 'Hello, world')
Hello, world

The reason is that in the first version, the type of test.doit is
InstanceType, and Python only 'binds' objects of type FunctionType to
MethodType.  MethodType is the type that contains an implicit first
'self' parameter.  If 'doit' has a __get__ attribute, it is called
whenever -class-.doit or -instance-.doit are accessed, and it returns
a bound method, or something else it likes.

A little more investigating reveals:

>>> def f(): pass
>>> dir( f )
['__call__', '__class__', '__delattr__', '__dict__', '__doc__',
'__get__', '__ge
tattribute__', '__hash__', '__init__', '__module__', '__name__',
'__new__', '__r

functions have a '__get__' attribute to perform this very thing.

More information about the Python-list mailing list