这是一个创建于 4148 天前的主题,其中的信息可能已经有所发展或是发生改变。
#背景
手头的项目是关于科学计算的。一个大的数据集,分别由以下几个文件组成:
+ crdArr => N个数据的坐标;
+ labelDict => N个数据的数据属性字典,如 labelDict["some_key"] 里面存着一个长度为N的某种属性的数据,相当于一个 speadsheet,key 作为 header 的索引键;
+ disMtx => N*N 的距离矩阵。
程序需要根据 labelDict 中的属性用数学表达式从 N 个数据中得到一个子集的 subset Index。每一个 subset index 作用到原有数据集会得到一个子集,这个子集生成一个叫做 collection 的对象然后交给后面的模块。。。
过去选取子集的代码都是写死在 python 里,用 Numpy (一个科学计算的 python 库,类似 Matlab),后来为了灵活,我在外面写了一个 json 的配置文件,把要设置的参数全部放进去。so far so good。
问题是,选取子集需要一个可能互相嵌套的数学表达式,比如:
idx = (labelDict["age"] > 30 && labelDict["age"] < 40) && (labelDict["occupation"] == "teacher")
这种表达式很容易用 numpy 的语法实现。但是 json object 是一个较为 flat 的结构,我没法在里面实现数学表达式的复杂逻辑和互相嵌套。目前在 json 文件中我只能把选取逻辑做成一个 list,然后一条一条的做逻辑运算,但很显然这种平坦结构的表达无法实现嵌套,可是如果用 json 来写一个数学表达式显然不合适。
还有一个原因,就是这个项目需要用户在程序执行的时候动态选取一个子集,这就是没法把选取子集的代码写死在 python 里的原因,同样,json 的配置文件也只是一个暂时的策略。我需要一个 GUI 来让用户输入可能的数学表达式来提取他子集需要的数据子集。所以我没法用 GUI 的控件来让用户设定子集选取表达式,而是想叫用户直接在文本框输入这种表达式。问题来了!!
# 问题
我觉得我完全没必要自己重新发明一个 正则表达式来 parse 用户输入的表达式,或者导入什么 Excel 的模块来完成这个任务。因为 Numpy 的语法本身就很清晰易懂。
所以我决定用 Python 自己的 eval 或者 complie 来提取用户在文本框输入的 Numpy 表达式。
可是,,,
首先这种方式很不安全,用户可以输入任何 python 代码,虽然我的程序不是网络程序,只是个科学计算软件,但是总觉得不放心。
理想方式是创建一个沙河机制,用户在文本框输入的 numpy 表达式在一个沙盒中 eval,有限的 namespace,有限的权限。这样基本上限制用户只能输入应该输入的。
# 实验
我刚刚做了个实验,写了一个 py 文件:
arr = array([1,2,3,4])
ss = sum(arr)
用 python 直接执行这个文件是不行的,因为 array() 函数不在命名空间中。
然后我打开 ipython
$ ipython
$ from numpy import array
$ excufile("the_file_I_mentioned_above.py")
$ print arr
$ print ss
以上可以执行,说明 excufile 是不管上下文的,需要我提前配置好上下文环境。
可问题是,我怎样限制用户在 eval 里面的输入,如何创建一个安全的执行环境?
第 1 条附言 · 2013-07-18 00:38:02 +08:00
搞定了。
之间有点小插曲,被 python 的参数传递机制给坑了。
我在 json 的配置文件里定义了个域,之间把 numpy 的表达式写了进去作为一个字符串,然后从程序中 eval 这个字符串,eval 的另一个参数 globals 我直接讲 labelDict (字典类型)传了进去。可是程序总是执行的不对。在该函数调用的外面,有一个变量也是 labelDict 是原始。我发现一个坑爹的现象。
在 eval(subsetString, labelDict) 后 labelDict 的类型从原来单纯的 数据字典,变成了 python 全局环境字典。anyway,后来我发现,在这个函数调用过后,labelDict 在该函数调用支出的 父函数的类型也发生了突变。
后来我改为 eval(subsetString, labelDict.copy()) 便没事了。
昨天看了一片文章,说 python 函数参数突变类型,今天就遇上了类似的坑,真是好险。。。
2 条回复 • 1970-01-01 08:00:00 +08:00
|
|
1
dndx 2013-07-17 09:10:27 +08:00 via iPad 1
|