creating a python function at runtime with specified argument names
我想这个功能:
1 2 | def f(x,y): return x+y |
如果我使用
现在想一想创建另一个函数
1 2 | def g(a,b): return f(a,b) |
有没有办法这样做吗?Lambda表达式是几乎是正确的,但我只能在编译时指定参数名称。
1 | g = lambda *p: f(*p) |
我想创建一个函数在运行时基于一dynamically列表L(例如
这是一种有点老套的方法,首先用修改创建一个新的函数,然后用它替换原来的代码。这主要是因为
我从@aaronasterling的回答中得到了这个想法(他说这个想法是从MichaelFoord的空间博客"无私的Python"中得到的)。它很容易成为一个装饰师,但我不认为这是有帮助的基础上,你告诉我们的预期用途。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 | import types def change_func_args(function, new_args): """ Create a new function with its arguments renamed to new_args.""" code_obj = function.func_code assert(0 <= len(new_args) <= code_obj.co_argcount) # the arguments are just the first co_argcount co_varnames # replace them with the new argument names in new_args new_varnames = tuple(list(new_args[:code_obj.co_argcount]) + list(code_obj.co_varnames[code_obj.co_argcount:])) # type help(types.CodeType) at the interpreter prompt for information new_code_obj = types.CodeType(code_obj.co_argcount, code_obj.co_nlocals, code_obj.co_stacksize, code_obj.co_flags, code_obj.co_code, code_obj.co_consts, code_obj.co_names, new_varnames, code_obj.co_filename, code_obj.co_name, code_obj.co_firstlineno, code_obj.co_lnotab, code_obj.co_freevars, code_obj.co_cellvars) modified = types.FunctionType(new_code_obj, function.func_globals) function.__code__ = modified.__code__ # replace code portion of original if __name__ == '__main__': import inspect def f(x, y): return x+y def g(a, b): return f(a, b) print('Before:') print('inspect.getargspec(g).args: {}'.format(inspect.getargspec(g).args)) print('g(1, 2): {}'.format(g(1, 2))) change_func_args(g, ['p', 'q']) print('') print('After:') print('inspect.getargspec(g).args: {}'.format(inspect.getargspec(g).args)) print('g(1, 2): {}'.format(g(1, 2))) |
输出:
1 2 3 4 5 6 7 | Before: inspect.getargspec(g).args: ['a', 'b'] g(1, 2): 3 After: inspect.getargspec(g).args: ['p', 'q'] g(1, 2): 3 |
我觉得你想要这样的东西:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | import inspect import math def multiply(x, y): return x * y def add(a, b): return a + b def cube(x): return x**3 def pythagorean_theorum(a, b, c): return math.sqrt(a**2 + b**2 + c**2) def rpc_command(fname, *args, **kwargs): # Get function by name f = globals().get(fname) # Make sure function exists if not f: raise NotImplementedError("function not found: %s" % fname) # Make a dict of argname: argvalue arg_names = inspect.getargspec(f).args f_kwargs = dict(zip(arg_names, args)) # Add kwargs to the function's kwargs f_kwargs.update(kwargs) return f(**f_kwargs) |
用途:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | >>> # Positional args ... rpc_command('add', 1, 2) 3 >>> >>> # Keyword args ... rpc_command('multiply', x=20, y=6) 120 >>> # Keyword args passed as kwargs ... rpc_command('add', **{"a": 1,"b": 2}) 3 >>> >>> # Mixed args ... rpc_command('multiply', 5, y=6) 30 >>> >>> # Different arg lengths ... rpc_command('cube', 3) 27 >>> >>> # Pass in a last as positional args ... rpc_command('pythagorean_theorum', *[1, 2, 3]) 3.7416573867739413 >>> >>> # Try a non-existent function ... rpc_command('doesntexist', 5, 6) Traceback (most recent call last): File"<stdin>", line 2, in <module> File"<stdin>", line 6, in rpc_command NotImplementedError: function not found: doesntexist |
使用关键字参数如何?
1 2 3 4 5 | >>> g = lambda **kwargs: kwargs >>> g(x=1, y=2) {'y': 2, 'x': 1} >>> g(a='a', b='b') {'a': 'a', 'b': 'b'} |
类似:
1 | g = lambda **kwargs: f(kwargs.get('a', 0), kwargs['b']) |
或者假设您只想使用以下值:
1 2 3 4 5 | >>> g = lambda **kwargs: f(*kwargs.values()) >>> def f(*args): print sum(args) ... >>> g(a=1, b=2, c=3) 6 |
在任何情况下,使用
您可以使用*args和*kwargs
假设您在运行时生成一个动态函数
1 2 3 4 | def func(): def dyn_func(*args, **kwargs): print args, kwargs return dyn_func |
然后可以在生成的函数中使用参数
1 2 | f = func() f(test=1) |
将给予:
1 | () {'test': 1} |
那么就可以根据您的需要管理arg了