This is hard. i want to not only create methods dynamically but also want to associate decorators with them. This is what I tried
import inspect
import types
class Dynamo(object):
pass
def call_me_dec(func):
print 'I am here'
return func
def add_dynamo(cls,i):
# @call_me_dec
def innerdynamo(self):
print "in dynamo %d" % i
return i
innerdynamo.__doc__ = "docstring for dynamo%d" % i
innerdynamo.__name__ = "dynamo%d" % i
setattr(cls, innerdynamo.__name__, innerdynamo)
def add_decorators(cls):
for name, fn in inspect.getmembers(cls):
if isinstance(fn, types.UnboundMethodType):
setattr(cls, name, call_me_dec(fn))
for i in range(2):
add_dynamo(Dynamo, i)
add_decorators(Dynamo)
d=Dynamo()
d.dynamo0()
d.dynamo1()
The output is:
I am here
I am here
in dynamo 0
in dynamo 1
Expected output:
I am here
in dynamo 0
I am here
in dynamo 1
Please explain why is this happening and how can I get the desired result?
You are seeing that because the decorator code is called at creation of the decorated function, not when the function is called. If you want to have the code run on call, you need to have the decorator return a callable (typically a closure) that calls the decorated method. Ex:
def call_me_dec(func):
print 'Decorating %s' % func
def func_wrapper(*args, **kwargs):
print 'Calling %s' % func
return func(*args, **kwargs)
return func_wrapper
Decorator syntax is just syntactical sugar. Remember:
def func():
pass
func = deco(func)
is equivalent to
@deco
def func():
pass
Either way, you end up with the func label in the local namespace referencing the object that is returned from passing func as explicitly defined to deco. Decorator syntax bundles some extra checking (like making sure the input and output to and from deco are always callables), but basically, if something would work a given way in example 1, it will work that way in example 2.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With