Python 开发过程中遇到的问题记录
写在前面
近期使用Python编写了一段项目维护脚本。期间遇到了不少问题,比如Python版本兼容问题,中文问题等。本篇将遇到的问题整理分享给大家,不定期更新中。
文件编码问题
如果在文件中出现了中文,我们必须要指定文件编码为UTF-8格式,否则执行时会出错。需要在文件头添加:
# -*- coding:utf-8 -*-
简化Python执行方式
一般来说,执行python程序的方式为
python xxx.py
这种是标准的运行Python程序命令。但是显得较为啰嗦。我们可以在py文件开头添加:
#!/usr/bin/python
然后给此文件赋予执行权限,然后就可以使用:
./xxx.py
方式执行这个Python脚本了。
获取用户输入不回显
输入不回显典型的使用场景为提示用户输入密码之时。如果我们使用Shell编程,可以使用read
命令的-s
参数:
read -s PASSWORD
该命令将用户接下来输入的内容保存到PASSWORD
变量中,且用户输入时不回显。
在Python中我们可以使用getpass
库来完成这项工作。该方式兼容Python2和3。
import getpass
password = getpass.getpass("Please enter your password: ")
获取是否以root用户执行
实践中我们会遇到需要检测当前执行Python脚本的用户这种场景。比如我们编写的安装脚本要求用root用户执行。在Python中可使用os.getuid()
方法获取运行当前脚本的uid。root用户的uid为0,所以仅需对比获取到的uid是否为0,即可判断当前执行的用户是否为root用户。
import
def is_running_as_root():
return os.getuid() == 0
Python import搜索路径
有时候我们在IDE编写好的脚本放到服务器上执行会提示import错误,要import的东西找不到。这时候我们需要配置Python的import搜索路径。
Python的import搜索路径保存在sys.path
变量中,为数组类型。我们可以把它打印出来,查看当前的path配置。
import sys
print(sys.path)
修改sys.path
的方法有两种。
- 使用
sys.path.append(search_path)
追加新的搜索路径到sys.path
数组中。 - 配置
PYTHONPATH
环境变量。需要注意的是此方法仅在当前会话中生效。
Python 2和3的兼容问题
input和raw_input
在Python 3中只有input
函数。作用为获取标准输入。例如我们编写:
username = input("Please input your name: ")
执行的时候会首先打印出Please input your name:
提示语,然后将用户输入的字符串保存在username变量中。
但是在Python 2中,功能相同的函数却叫做raw_input
,但是在Python 3中没有这个函数。input
函数在Python 2中也有,但作用完全不同。Python 2的input
函数会把用户的输入作为表达式去解析,如果用户的输入无法解析,会抛出SyntaxError
。
所以说获取用户输入,在Python 2中使用raw_input
,在Python 3中则需要用input
。
另外,在Python 2和3中均可以使用如下方式读取用户输入:
import sys
username = sys.stdin.readline(10).strip()
print(username)
sys.stdin.readline()
后面的参数为用户输入的长度限制,如果用户输入的长度超过限制,会被截断。
sys.stdin.readline()
和input
以及raw_input
最大的不同是sys.stdin.readline()
会捕获到结尾的换行符\n
。因此需要加一个strip
,去掉用户输入末尾的换行符。
字典内容的排序问题
例如下面的一段程序:
if __name__ == '__main__':
_dict = {
"1": "一",
"2": "二",
"3": "三",
"4": "四"
}
for k, v in _dict.items():
print("key: {} | value: {}".format(k, v))
如果我们在Python 3.6及以上版本执行,每次的输出都是:
key: 1 | value: 一
key: 2 | value: 二
key: 3 | value: 三
key: 4 | value: 四
也就是说,在Python3.6及其以上的版本,字典内元素是有序的。
但是在Python3.6以下的版本,字典内元素的顺序是无法保证的。
为了解决这个问题,我们可以使用Python提供的collections.OrderedDict
。使用方式如下所示:
import collections
_dict = collections.OrderedDict()
_dict['1'] = 'A'
_dict['2'] = 'B'
_dict['3'] = 'C'
_dict['4'] = 'D'
for k,v in _dict.items():
print(k, v)
以上程序无论在Python 2还是3中运行多少次,输入的结果顺序都不会改变,OrderedDict
是可以保证内部的元素顺序的。
获取Python版本的方法
import sys
version = sys.version_info
print(version)
执行后我们可以看到类似如下输出:
sys.version_info(major=3, minor=8, micro=10, releaselevel='final', serial=0)
到这里就很清晰了。比如我们要获取Python的主版本号,只需要获取sys.version_info.major
变量的值即可。
获取Linux发行版
在Python 2中我们可借助于platform
包,方式如下:
import platform
print(platform.dist())
输出是一个元组,比如:
('centos', '7.4.1708', 'Core')
但是在Python 3中执行上述脚本会报错:
AttributeError: module 'platform' has no attribute 'dist'
原因是Python 3种的platform没有dist这个属性。那么问题来了,在Python 3中我们该怎么办?
可以借助distro
库。这个库是Python 3独有的,不能在Python 2中使用。
import distro
print(distro.linux_distribution())
问题似乎是解决了,但是这两种写法只能在对应的Python版本运行,无法兼容。为了解决这个问题,我们可以使用前面介绍的判断Python版本的方法,在不同版本调用不同的方法。如下所示:
import sys
def get_distribution():
if sys.version_info.major == 2:
import platform
return platform.dist()
else:
import distro
return distro.linux_distribution()
我们还可以判断platform
这个包是否具有dist
,来决定使用platform.dist()
还是distro.linux_distribution()
方式。
def get_distribution():
import platform
if hasattr(platform, "dist"):
return platform.dist()
else:
import distro
return distro.linux_distribution()