Python2和Python3在语法和模块的使用上会有一些差别。目前通常使用Python3编写脚本,实际工作中有很多运维或者测试脚本还在使用Python2运行。这时可以使用python包3to2将Python3脚本直接转为Python2脚本。
但3to2有时并不那么智能,它对于Python2~Python3之间发生变更的语法比较有效,但对于部分Python3新引入的特性,并不能很好的转化。以下记录了工作中踩过的一些坑,仅供参考。
1. init.py文件
在Python 3.2及之前的版本中,如果要将一个目录声明为包,需要在该目录中创建一个空的__init__.py
文件。Python 3.3+版本以后,Python3具有隐式命名空间包,允许它创建不带__init__.py
文件的包。如果你是在python3.3以上的版本编写代码,并且没有创建__init__.py
文件。那么在使用3to2转换代码后,需要手动在package文件夹下创建__init__.py
文件。如下目录:
package/
__init__.py
module
可以像这样导入包和模块:
import package.module
如果是将开源的第三方库打包放入代码中,更推荐下面这种导入方式。这种方式会将package文件夹加入模块的搜索路径,同时也会搜索系统默认路径。
sys.path.append("package")
import module
2. ping3库
ping3是一个用于执行ping命令的Python库。当你的python脚本需要同时兼容windows和linux时,ping指令会有所不同,使用ping3库可以保证跨平台的兼容性。但是,ping3库只支持python3.x。如果你要在python2.x环境中使用ping,可以自己封装一个ping函数
import os
import platform
import subprocess
def ping(host)
param = "-n" if platform.system().lower() == "windows" else "-c"
command = ["ping", param, "1", host]
devnull = open(os.devnull, "w")
res = subprocess.call(command, stdout=subprocess.PIPE, stderr=devnull) == 0
devnull.close()
return res
使用platform模块判断当前平台为windows还是linux。将输出重定向到os模块的devnull,能保证windows/linux平台兼容性。
3. 线程池/多线程
python中线程池的使用可以简化线程管理。但要注意,ThreadPoolExecutor (线程池)是在python3.2
版本引入的,如果你需要使用3to2使你的脚本在python2.x中运行,那么不要使用ThreadPoolExecutor,老老实实使用threading模块管理你的线程。
4. 生成有序列表
我在python3中编写了以下语句,用来生成一个0 ~ n-1的有序列表
my_list=list(range(0, n))
当使用3to2后,它变成了
my_list=xrange(0, n)
这样生成的my_list并不是一个list对象,导致后续调用报错。目前原因不明。
5. 有序字典
在python3.5及以前,字典是不能保证顺序的。python3.6已经使字典变得有序。如果你需要保证字典的顺序,可以使用collections.OrderedDict
来创建有序字典。
dict = {"a": "A", "b": "B"}
print(dict)
import collections
order_dict = collections.OrderedDict()
order_dict["a"] = "A"
order_dict["b"] = "B"
print(order_dict)
6. 写入文件报错
我在python3中写了如下代码,用于将数据写入到csv文件中。
with open("data.csv", "w", newline="") as file:
writer = csv.writer(file)
writer.writerow(my_list)
当使用3to2转换后,出现如下报错:
# TypeError: write() argument 1 must be unicode, not str
需要在打开文件时指定编码格式:
import codecs
with codecs.open("data.csv", "w", "utf-8")as file:
writer = csv.writer(file)
writer.writerow(my_list)