控制功能评估上下文

时间:2017-05-02 16:21:37

标签: python python-3.x exec eval evaluation

我为用户提供了定义自定义函数f的机会 执行取决于他们选择的各种自定义参数parms

  • 他们有责任确保他们需要的每个参数都是 为要评估的函数定义。
  • 我有责任运行此功能。

令人讨厌的解决方案是让他们将自定义代码编写为字符串,然后再编写 用他们需要的参数替换他们的变量名,如:

## User side
parms = {'a': 5,
         'b': 89,
         'c': 'third_user_parameter'}
f=\
"""# any operation, user is free:
if len(c) > 10:
    result = sum(ord(char) for char in c)
else:
    result = a + b
"""

## My side
exec(f, parms, parms)
result = parms['result']
print(result)

这种方法的主要问题(除了result必须这样的事实 保留为关键字)用户必须在字符串中定义她的过程 很不方便。

有没有办法可以让用户定义一个实际的功能,然后再使用 它?
我怎么能用它们的参数作为变量来评估它们的函数 我需要它吗?

简而言之,我希望这可行,但事实并非如此:

## User side
parms = {'a': 5,
         'b': 89,
         'c': 'third_user_parameter'}
def f():
    if len(c) > 10:
        return sum(ord(char) for char in c)
    else:
        return a + b


## My side
eval('f()', parms, parms) # NameError: name 'f' is not defined
parms.update({'f': f})
eval('f()', parms, parms) # NameError: name 'c' is not defined
exec('f()', parms, parms) # NameError: name 'c' is not defined

在不改变用户方面的情况下,有没有办法可以在...中执行f() parms的“上下文”并得到预期的结果?

1 个答案:

答案 0 :(得分:0)

好的,感谢blubberdiblub条评论,事实证明我主要需要将用户的表达式变量参数分开,而无需用户需要两次定义他们的参数。

一个肮脏的解决方案是使用f高举f.__globals__.update(parms)执行上下文,但这是非常糟糕的python,因为它与globals()混淆。

我最喜欢的解决方案是使用python的 kwargs 功能来区分变量和参数。这也是一个肮脏的劫机,它也使用魔法,但我们仍然是toying with less powerful forces

## User side
def user_expression(x,
        # parameters
        a=5,
        b=89,
        c='third_user_parameter'
        ):
    if len(c) > 10:
        intermediate = sum(ord(char) for char in c)
        return x + intermediate
    else:
        return x - b

## My side;
# extract parameters, encoded as kwargs:
values = user_expression.__defaults__
nb_kwargs = len(values)
nb_args = user_expression.__code__.co_argcount
names = user_expression.__code__.co_varnames[nb_args - nb_kwargs:nb_args]
parms = {k: v for k, v in zip(names, values)}
# evaluate the expression with these parameters or other ones:
result = user_expression(42, **parms)
print(result)