. , ast. , , - , - , simple_eval.
import ast
def get_multi_lambda(expr, args=()):
code_stmt = ast.parse(expr, mode='eval')
collector = NameCollector()
collector.visit(code_stmt)
arg_set = set(args)
if arg_set - collector.names:
raise TypeError("unused args", arg_set - collector.names)
elif collector.names - arg_set:
raise TypeError("attempted nonlocal name access",
collector.names - arg_set)
func_node = create_func_node(args, code_stmt)
code_obj = compile(func_node, "<generated>", "eval")
return eval(code_obj, {}, {})
def create_func_node(args, code_stmt):
lambda_args = ast.arguments(
args=[ast.arg(name, None) for name in args],
vararg=None, varargannotation=None, kwonlyargs=[], kwarg=None,
kwargannotation=None, defaults=[], kw_defaults=[]
)
func = ast.Lambda(args=lambda_args, body=code_stmt.body)
expr = ast.Expression(func)
ast.fix_missing_locations(expr)
return expr
class NameCollector(ast.NodeVisitor):
"""Finds all the names used by an ast node tree."""
def __init__(self):
self.names = set()
def visit_Name(self, node):
self.names.add(node.id)
func = get_multi_lambda('a / b + 1', ['a', 'b'])
print(func(3, 4))
, -- , , , . . min, max, sum ..