最近使用别人在python2.x中写的项目,由于环境原因,必须在python3.x环境下,运行这个项目,于是遇到了一点问题,将解决探索的过程,以及最终的解决方案总结如下。
在python3.x和python2.x中有些内置的函数还是存在变化,比如python2.x中的对于大量数据非常省内存的迭代器xrange,在python3.x中被整合到了range中,因而不会有python2.x中存在的调用迭代器不同,造成性能不同的问题,这样以来,在python3.x中,就抛弃了xrange这个迭代器。这样也带来了问题,最近得到的一个项目的代码是用python2.x写的,但是由于技术原因,必须在python3.x下运行,然而报错就出现在了xrange的调用上,python3.x下没有xrange调用了。首先想到的办法是将xrange调用改成range调用,但是发现不止一处地方使用了xrange,这样修改起来比较麻烦了。于是想着,直接将xrange的调用指向range就好了,比如在代码中加入如下的赋值:
xrange = range
这样可以解决在当前的文件或者模块下生效,但是对于嵌套的项目代码,其对于一个变量,这个例子中是xrange这个变量,搜索的顺序是:
1、先在当前 (嵌套的或 lambda) 函数的命名空间中搜索
2、然后是在父函数的命名空间中搜索
3、接着是模块命名空间中搜索
4、最后在内置命名空间中搜
因而,如果只是在入口的文件中,比如类似C++的main函数声明的文件中添加了xrange=range的赋值,一般来说还是会报错,这样的赋值要放到模块的命名空间才行,这样的话,这个赋值语句又会不断的复制到各处,导致文件的冗余,因而还有一个办法,在搜索书序的最后,会在内置命名空间中搜索,比如你在项目中任意一个地方调用range函数,这个函数最终会在内置命名空间中找到具体的声明,所以将上述赋值增加到内置命名空间中,就可以实现一次赋值,整个项目不出问题的情况,因而最终折中的解决办法是在入口文件中加入下列声明:
globals()['builtins'].dict['xrange'] = range
其中builtins就是内置的命名空间,而内置函数的命名全部在其dict中,可以尝试print一下builtins的_dict就可以看到内置函数了。
其实有个更为简单的解决办法就是把xrange放入全局命名空间:
global xrange
xrange = range