python - 不使用字典动态创建变量
问题描述
用例 - 我正在使用在另一个系统中创建的 python 代码,并将其分解为单独的函数并将它们连接在一起。这项工作的全部目的是将由于许多业务原因我们没有编写的大型 Python 函数分解成更小的 Python 函数。
我可以获取代码,解析变量,并在执行此操作时任意将它们放入 dict 中,但这不仅仅是一点点工作,我想在此之前将其运行到地面。
我知道我们几乎不 应该这样做,但我需要这样做,因为我是为我没有编写的函数生成包装器的代码,我需要在函数内部动态创建变量。我也不能使用exec
,因为该值可能是一个复杂的结构(例如,一个字典)。
因此,我们所做的重点是要求原始作者不对传入的代码进行任何更改,同时仍然跨多个独立实体执行它。
就像这里列出的示例一样 - 我们在第一个出口(理想情况下是函数、lambdas 和所有变量)中捕获尽可能多的状态,并在第二个函数中重新设置它们,以便以前具有相同的两个函数范围和上下文可以在没有更改的情况下执行。
这是一个可重现的代码块(所有与此无关b
的代码都是我可以用来包装赋值的代码:
原来的:
def original_function():
b = 100
b = b + 20
生成的函数:
def fun_1() -> str:
import dill
from base64 import urlsafe_b64decode, urlsafe_b64encode
from types import ModuleType
b = 100
locals_keys = frozenset(locals().keys())
global_keys = frozenset(globals().keys())
__context_export = {}
for val in locals_keys:
if not val.startswith("_") and not isinstance(val, ModuleType):
__context_export[val] = dill.dumps(locals()[val])
for val in global_keys:
if not val.startswith("_") and not isinstance(val, ModuleType):
__context_export[val] = dill.dumps(globals()[val])
b64_string = str(urlsafe_b64encode(dill.dumps(__context_export)), encoding="ascii")
from collections import namedtuple
output = namedtuple("FuncOutput", ["context"])
return output(b64_string)
def fun_2(context):
import dill
from base64 import urlsafe_b64encode, urlsafe_b64decode
from types import ModuleType
__base64_decode = urlsafe_b64decode(context)
__context_import_dict = dill.loads(__base64_decode)
for k in __context_import_dict:
val = dill.loads(__context_import_dict[k])
if globals().get(k) is None and not isinstance(val, ModuleType):
globals()[k] = val
b = b + 20
output = fun_1()
fun_2(output[0])
运行此程序时出现的错误是:
UnboundLocalError: local variable 'b' referenced before assignment
谢谢大家的帮助!
解决方案
好的,在我理解了这些问题之后,这很容易解决。老实说,这更有意义 - 因为我是从外部获取代码(作为字符串),所以我应该挂载必要的全局变量并在封闭环境中执行是有道理的。
明确 - 这是在用户环境中执行的,因此安全性不是问题。但这有效!
def fun_1() -> str:
import dill
from base64 import urlsafe_b64decode, urlsafe_b64encode
from types import ModuleType, FunctionType
# CODE FROM EXTERNAL
b = 100
# END CODE
locals_keys = frozenset(locals().keys())
global_keys = frozenset(globals().keys())
__context_export = {}
for val in locals_keys:
if (
not val.startswith("_")
and not isinstance(val, ModuleType)
and not isinstance(val, FunctionType)
):
__context_export[val] = dill.dumps(locals()[val])
for val in global_keys:
if (
not val.startswith("_")
and not isinstance(val, ModuleType)
and not isinstance(val, FunctionType)
):
__context_export[val] = dill.dumps(globals()[val])
b64_string = str(urlsafe_b64encode(dill.dumps(__context_export)), encoding="ascii")
from collections import namedtuple
output = namedtuple("FuncOutput", ["context"])
return output(b64_string)
def fun_2(context):
import dill
from base64 import urlsafe_b64encode, urlsafe_b64decode
from types import ModuleType, FunctionType
from pprint import pprint as pp
__base64_decode = urlsafe_b64decode(context)
__context_import_dict = dill.loads(__base64_decode)
variables = {}
for k in __context_import_dict:
variables[k] = dill.loads(__context_import_dict[k])
loc = {}
# CODE FROM EXTERNAL
inner_code_to_execute "b = b + 20"
# END CODE
exec(inner_code_to_execute, variables, loc)
print(loc["b"])
output = fun_1()
fun_2(output[0])
推荐阅读
- css - 如何重新定位 google rechapta 弹出窗口?
- android - Google Play 服务 SMS 和 CALL LOGS 权限问题
- android - 如何在Android中的两个位置之间使用折线绘制自己的路线
- powershell - 如何解析 .txt 文件并知道没有分配给列出的卷的字母
- python - 如何提取特定字符之间的单词
- kubernetes - Nginx 控制器服务名称配置错误
- c# - RDOPOP3Account 的 SMTP 密码未更新
- angular - Primeng下拉自动对焦
- java - 制作 JasperReports pdf 文件时如何解决格式错误的 URL 错误?
- html - 如何在加载时预选单选按钮(Express / NodeJS / EJS)?