I would like to set the default key-arguments of an instance method dynamically. For example, with
class Module(object):
def __init__(self, **kargs):
set-default-key-args-of-method(self.run, kargs) # change run arguments
def run(self, **kargs):
print kargs
We would have:
m = Module(ans=42)
m.run.im_func.func_code.co_argcount # => 2
m.run.im_func.func_code.co_varnames # => ('self','ans','kargs')
m.run.im_func.func_defaults # => (42,)
m.run() # print {'ans':42}
I tried something with types.CodeType (which I don't really understand) for a function (not a method) and got it to work (well not-to-fail), but the added key-arguments did not show in the kargs dictionary of the function (it only print {})
The change has to be done for the current instance only. Actually, I am using a class right now (I'm OO in my mind) so I would like to do it with a class method, but a function is maybe better. Something like:
def wrapped_run(**kargs):
def run(**key_args):
print key_args
return wrap-the-run-function(run, kargs)
run = wrapped_run(ans=42)
run.func_code.co_argcount # => 1
run.func_code.co_varnames # => ('ans','key_args') ## keep the 'key_args' or not
run.func_defaults # => (42,)
run() # print {'ans':42}
Any advise or idea is welcome.
A little on the context:
The Module class is some kind a function wrapper, which can be use to include the lower-end function in a dataflow system automatically but add intermediate procedures. I would like the module run function (actually, it will probably be it's __call___ function) to have the correct API in order for the dataflow system to nicely generate the correct module's input transparently.
I'm using python 2.7
For the sake of closure, I give the only solution that was found: use exec
(proposed by mgilson)
import os, new
class DynamicKargs(object):
"""
Class that makes a run method with same arguments
as those given to the constructor
"""
def __init__(self, **kargs):
karg_repr = ','.join([str(key)+'='+repr(value) \
for key,value in kargs.iteritems()])
exec 'def run(self,' + karg_repr + ',**kargs):\n return self._run(' + karg_repr + ',**kargs)'
self.run = new.instancemethod(run, self)
def _run(self, **kargs):
print kargs
# this can also be done with a function
def _run(**kargs):
print kargs
def dynamic_kargs(**kargs):
karg_repr = ','.join([str(key)+'='+repr(value) for key,value in kargs.iteritems()])
exec 'def run(' + karg_repr + ',**kargs):\n return _run(' + karg_repr + ',**kargs)'
return run
# example of use
# --------------
def example():
dyn_kargs = DynamicKargs(question='ultimate', answer=42)
print 'Class example \n-------------'
print 'var number:', dyn_kargs.run.im_func.func_code.co_argcount
print 'var names: ', dyn_kargs.run.im_func.func_code.co_varnames
print 'defaults: ', dyn_kargs.run.im_func.func_defaults
print 'run print: ',
dyn_kargs.run()
print ''
dyn_kargs = dynamic_kargs(question='foo', answer='bar')
print 'Function example \n----------------'
print 'var number:', dyn_kargs.func_code.co_argcount
print 'var names: ', dyn_kargs.func_code.co_varnames
print 'defaults: ', dyn_kargs.func_defaults
print 'run print: ',
dyn_kargs()
The example
function prints:
Class example
-------------
var number: 3
var names: ('self', 'answer', 'question', 'kargs')
defaults: (42, 'ultimate')
run print: {'answer': 42, 'question': 'ultimate'}
Function example
----------------
var number: 2
var names: ('answer', 'question', 'kargs')
defaults: ('bar', 'foo')
run print: {'answer': 'bar', 'question': 'foo'}
However:
repr