Decorators using instance variables
castironpi
castironpi at gmail.com
Thu Aug 21 23:49:12 EDT 2008
On Aug 21, 9:22 pm, robert2821 <robert2... at verizon.net> 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')
>
> Dec.py
> < 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')
Output:
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