控制函数求值上下文
Control a function evaluation context
我为我的用户提供了一个定义自定义函数的机会 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
在不改变用户端的情况下,有没有一种方法可以在
parms
的 "context" 并得到预期的结果?
好的,感谢 blubberdiblub 的评论,事实证明我主要需要将用户的表达式 变量 与他们的 参数 , 用户无需定义参数两次。
一个肮脏的解决方案是用 f.__globals__.update(parms)
劫持 f
执行上下文,但这真的很糟糕 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)
我为我的用户提供了一个定义自定义函数的机会 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
在不改变用户端的情况下,有没有一种方法可以在
parms
的 "context" 并得到预期的结果?
好的,感谢 blubberdiblub 的评论,事实证明我主要需要将用户的表达式 变量 与他们的 参数 , 用户无需定义参数两次。
一个肮脏的解决方案是用 f.__globals__.update(parms)
劫持 f
执行上下文,但这真的很糟糕 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)