为了让拟合程序能按照一个模型列表依次进行计算,在之前的程序中我大量的使用了eval函数,将字符串转为计算式。这样便可以建立一个以字符串形式储存公式的列表,阅读、修改和循环执行起来都非常方便。

一开始公式中的变量名称都是规定死的,后来我又想对这个功能进行扩充,实现自定义变量名,更加方便阅读。于是就现在命令行中尝试了:
exec(‘a, b, c’ = [1, 1, 0])
发现可以执行后就将其添加进了函数中,于是就上演了一场论坑是怎么形成的故事。

一开始发现这句没有执行的时候觉得很不可思议,明明在console中验证过没有问题的。和上次的故事一样,中文搜索无果后转用英文,最开始看到的是这个帖子http://stackoverflow.com/questions/1463306/how-does-exec-work-with-locals,里面倒是说了一个解决方法,尝试后发现的确管用,但当时没有仔细看下面的解释就开始找如何把新生成的字典替换回locals,也就是走上了修改locals的不归路。

熟悉python3的人一定一眼就看出来问题在哪,python3的locals是不能被修改的,最后还是认真看了这个帖子中的回复:
http://stackoverflow.com/questions/1450275/modifying-locals-in-python
回复内容如下:

If you are using Python 3.x, it does not work anymore because locals are optimized as an array at runtime, instead of using a dictionary.

When Python detects the “exec statement”, it will force Python to switch local storage from array to dictionary. However since “exec” is a function in Python 3.x, the compiler cannot make this distinction since the user could have done something like “exec = 123”.

http://bugs.python.org/issue4831

To modify the locals of a function on the fly is not possible without several consequences: normally, function locals are not stored in a dictionary, but an array, whose indices are determined at compile time from the known locales. This collides at least with new locals added by exec. The old exec statement circumvented this, because the compiler knew that if an exec without globals/locals args occurred in a function, that namespace would be “unoptimized”, i.e. not using the locals array. Since exec() is now a normal function, the compiler does not know what “exec” may be bound to, and therefore can not treat is specially.

所以之前在console中可以执行是因为在globals下面,写函数里面就变成了在locals下面,也就不能被修改了。这下总算是知其然也知其所以然了,同时也就放弃了这条不归路,然而前后又坑了我三个多小时,长叹一声啊……