使用 ast 创建具有默认值的仅关键字参数的函数
Using ast to create a function with a keyword-only argument that has a default value
我正在尝试使用 ast
动态创建一个函数,该函数的参数只有关键字,而且参数具有默认值。但是,生成的函数仍然需要参数,如果未通过,将引发 TypeError
。
这是创建函数的代码 f
:
import ast
import types
module_ast = ast.Module(
body=[
ast.FunctionDef(
name='f',
args=ast.arguments(
args=[],
vararg=None,
kwarg=None,
defaults=[],
kwonlyargs=[
ast.arg(
arg='x',
lineno=1,
col_offset=0,
),
],
kw_defaults=[
ast.Num(n=42, lineno=1, col_offset=0),
],
posonlyargs=[],
),
body=[ast.Return(
value=ast.Name(id='x', ctx=ast.Load(), lineno=1, col_offset=0),
lineno=1,
col_offset=0,
)],
decorator_list=[],
lineno=1,
col_offset=0,
)
],
type_ignores=[],
)
module_code = compile(module_ast, '<ast>', 'exec')
# This is the part that I'm suspicious of
f_code = next(c for c in module_code.co_consts if isinstance(c, types.CodeType))
f = types.FunctionType(
f_code,
{}
)
如果我print(ast.unparse(module_ast))
,我得到我期望的:
def f(*, x=42):
return x
按预期调用 f(x=100)
returns 100
,但调用 f()
会产生:
TypeError: f() missing 1 required keyword-only argument: 'x'
我怀疑问题出在我将 AST 转换为函数的过程中。我在这里看到了另一个问题的方法(不幸的是我没有 link )。它看起来有点狡猾,但我不确定该怎么做。
函数的默认参数值不是函数代码对象的一部分。它们不可能,因为默认值是在函数定义时创建的,而不是字节码编译时。对于 non-keyword-only 个参数,默认参数值存储在 __defaults__
中,对于 keyword-only 个参数,默认参数值存储在 __kwdefaults__
中。当您从 module_code
中提取 f_code
时,您不会获得任何有关默认值的信息。
执行函数定义,然后获取实际的函数对象:
namespace = {}
exec(module_code, namespace)
function = namespace['f']
我正在尝试使用 ast
动态创建一个函数,该函数的参数只有关键字,而且参数具有默认值。但是,生成的函数仍然需要参数,如果未通过,将引发 TypeError
。
这是创建函数的代码 f
:
import ast
import types
module_ast = ast.Module(
body=[
ast.FunctionDef(
name='f',
args=ast.arguments(
args=[],
vararg=None,
kwarg=None,
defaults=[],
kwonlyargs=[
ast.arg(
arg='x',
lineno=1,
col_offset=0,
),
],
kw_defaults=[
ast.Num(n=42, lineno=1, col_offset=0),
],
posonlyargs=[],
),
body=[ast.Return(
value=ast.Name(id='x', ctx=ast.Load(), lineno=1, col_offset=0),
lineno=1,
col_offset=0,
)],
decorator_list=[],
lineno=1,
col_offset=0,
)
],
type_ignores=[],
)
module_code = compile(module_ast, '<ast>', 'exec')
# This is the part that I'm suspicious of
f_code = next(c for c in module_code.co_consts if isinstance(c, types.CodeType))
f = types.FunctionType(
f_code,
{}
)
如果我print(ast.unparse(module_ast))
,我得到我期望的:
def f(*, x=42):
return x
按预期调用 f(x=100)
returns 100
,但调用 f()
会产生:
TypeError: f() missing 1 required keyword-only argument: 'x'
我怀疑问题出在我将 AST 转换为函数的过程中。我在这里看到了另一个问题的方法(不幸的是我没有 link )。它看起来有点狡猾,但我不确定该怎么做。
函数的默认参数值不是函数代码对象的一部分。它们不可能,因为默认值是在函数定义时创建的,而不是字节码编译时。对于 non-keyword-only 个参数,默认参数值存储在 __defaults__
中,对于 keyword-only 个参数,默认参数值存储在 __kwdefaults__
中。当您从 module_code
中提取 f_code
时,您不会获得任何有关默认值的信息。
执行函数定义,然后获取实际的函数对象:
namespace = {}
exec(module_code, namespace)
function = namespace['f']