正如可以使用type(name,base-classes,namespace-dict)创建动态类一样,是否可以创建动态函数?
我尝试过以下方面的做法:
>>> f = type("f", (function,), {})
NameError: name 'function' is not defined
Run Code Online (Sandbox Code Playgroud)
好的,所以我会很聪明,但是:
>>> def fn():
... pass
...
>>> type(fn)
<type 'function'>
>>> f = type("f", (type(fn),), {})
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: type 'function' is not an acceptable base type
Run Code Online (Sandbox Code Playgroud)
Python是否以与允许动态类相同的方式专门阻止动态函数的创建?
编辑:注意,我不允许任何使用exec ..因为我的问题是Python语言本身允许这样做.
提前致谢.
Anu*_*yal 37
还有types.FunctionType,你可以用它来动态地创建的功能,例如
def test_func(): print 'wow'
dynf = types.FunctionType(test_func.func_code, {})
dynf()
Run Code Online (Sandbox Code Playgroud)
输出:
wow
Run Code Online (Sandbox Code Playgroud)
您可能会反对这不是动态的,因为我正在使用来自另一个函数的代码,但这只是一个示例,有一种方法可以从python字符串生成代码,例如
dynf = types.FunctionType(compile('print "really WoW"', 'dyn.py', 'exec'), {})
dynf()
Run Code Online (Sandbox Code Playgroud)
输出:
really WoW
Run Code Online (Sandbox Code Playgroud)
现在这是动态的!
OP担心这种功能的动态特性,所以这是另一个例子
dynf = types.FunctionType(compile('test_func():\ntest_func()', 'dyn.py', 'exec'), globals())
dynf()
Run Code Online (Sandbox Code Playgroud)
输出:
wow
wow
Run Code Online (Sandbox Code Playgroud)
注意:像这样创建Function对象似乎有限制,例如传递参数并不容易,因为要传递参数我们需要传递正确的co_argcount,co_varnames和其他12个变量types.CodeType,理论上可以做到但是容易出错,更简单的方法是将字符串作为模块导入,并且您具有完整的功能,例如
import types
import sys,imp
code = """def f(a,b,c):
print a+b+c, "really WoW"
"""
module = imp.new_module('myfunctions')
exec code in module.__dict__
module.f('W', 'o', 'W')
Run Code Online (Sandbox Code Playgroud)
输出:
WoW really WoW
Run Code Online (Sandbox Code Playgroud)
Gar*_*tty 12
你需要研究一下collections.Callable,这只是定义时开始的好地方__call__.
from collections import Callable
class SomeCallableClass(Callable):
def __call__(self, x):
print(x)
some_function = SomeCallableClass()
some_function(1)
Run Code Online (Sandbox Code Playgroud)
将1输出作为输出.这允许您随意构造函数.
from collections import Callable
class SomeCallableClass(Callable):
def __init__(self, n):
self.n = n
def __call__(self, x):
for i in range(self.n):
print(x)
some_function = SomeCallableClass(2)
some_function("Two times.")
some_function = SomeCallableClass(3)
some_function("Three times.")
Run Code Online (Sandbox Code Playgroud)
这给了我们:
Two times.
Two times.
Three times.
Three times.
Three times.
Run Code Online (Sandbox Code Playgroud)
您可以使用它来构建您想要的复杂函数.
exec如果您准备生成抽象语法树(AST)并编译它们,则可以避免生成当时的源代码.它可能稍微好一点,因为数据可以始终保持结构化.
from ast import *
from types import *
function_ast = FunctionDef(
name='f',
args=arguments(args=[], vararg=None, kwarg=None, defaults=[]),
body=[Return(value=Num(n=42, lineno=1, col_offset=0), lineno=1, col_offset=0)],
decorator_list=[],
lineno=1,
col_offset=0
)
module_ast = Module(body=[function_ast])
module_code = compile(module_ast, "<not_a_file>", "exec")
function_code = [c for c in module_code.co_consts if isinstance(c, CodeType)][0]
f = FunctionType(function_code, {})
print f()
Run Code Online (Sandbox Code Playgroud)
上面的代码将打印出来42.
要获得生成的AST应该是什么的灵感,您可以使用:
print(dump(parse("def f(): return 42"), include_attributes=True))
Run Code Online (Sandbox Code Playgroud)
当然,AST在Python 2和Python 3中有所不同.
| 归档时间: |
|
| 查看次数: |
15234 次 |
| 最近记录: |