背景
用 Python 讨生活这么多年,我一直以来的一个观点就是 “在 Python 这个大环境下 import xxx 写完之后功能就实现了 50% ~ 80% 。”。
Python 的编码效率高主要原因在于一些通用的功能模块、算法、数据结构 ,前人已经做好了。我拿过来用就行了,经验上来看绝大多数问题都有对应的模块。所以后面 Python 这个系列打算把标准库和常用的第三方库讲一讲(又可以水两年)。作为标准库的第一篇我决定对 pwd 这个模块下手。
PWD 要解决的问题
这个库的目标简单到要死,一方面用于检查给定的用户是否存在,另一方面可用于用户读取用户的 uid,gid 等信息,总之就是读操作。
如果我们选择自己硬写的话,pwd 的功能也不是不可替代;但相比复用标准库我们的代码可能要长好多。下面写一个检查给定用户是否存在的功能。
#!/usr/bin/env python3
def has_user(name:str="root"):
"""
检查给定的用户在当前操作系统中是否存在
Parameter
---------
name: str
用户名
Return
------
bool
"""
# 参数处理(用户名后面是一个:号的,在这里加一个:可以把正则省略)
name = name.strip()+":"
if name == ":":
return False
# 检查操作系统上有没有这个用户
with open("/etc/passwd") as pwd_file_obj:
for line in pwd_file_obj:
if line.startswith(name):
return True
return False
if __name__ == "__main__":
users = ['root','mysql','notexistsuser']
for user in users:
print(f"{user} exists == {has_user(user)}")
# 测试一种异常的情况
user = "roo"
print(f"{user} exists == {has_user(user)}")
运行的效果
python3 main.py
root exists == True
mysql exists == False
notexistsuser exists == False
roo exists == False
检查一个用户是否存在都要这么多行代码,这并不 Pythonic 呀! 能不能 import 就完成 50%?
PWD 写法
标准库用的好效率低不了,先来看一下用 pwd 这个标准库模块,我们的代码要怎么重写。
#!/usr/bin/env python3
import pwd
def has_user(name:str="root"):
"""
检查给定的用户在当前操作系统中是否存在
Parameter
---------
name: str
用户名
Return
------
bool
"""
try:
return pwd.getpwnam(name) != None
except KeyError as err:
return False
if __name__ == "__main__":
users = ['root','mysql','notexistsuser']
for user in users:
print(f"{user} exists == {has_user(user)}")
# 测试一种异常的情况
user = "roo"
print(f"{user} exists == {has_user(user)}")
运行效果
python3 pwd-v1.py
root exists == True
mysql exists == False
notexistsuser exists == False
roo exists == False
PWD 自身有什么问题
其实对于 pwd 这个模块评价我也是经过好多年才做到一个客观 & 理性的。
1、一开始我认为它的问题就在于 API 接口命名不友好,本来一个好好的 get_pw_by_name 它硬给搞成了 getpwnam ,少写几个字母会这么爽吗?
2、后来因为一些工作上的原因(我们这边希望 MySQL DBA 要有 Debug MySQL 的能力),就这样我又把 C/C++ 从故纸堆里捡了回来,遥想当年就是看到下面这样一段 C 代码的时候顿悟的 pwd 模块。
#include<pwd.h>
#include<stdio.h>
int main() {
struct passwd *user;
user = getpwnam("root");
printf("%s \n",user->pw_name);
return 0;
}
运行效果
gcc use-pwd.c -o use-pwd && ./use-pwd
root
3、现在我觉得 pwd 库没有毛病,它忠实的“包装”了 C 库,做到了对 C 语言程序员友好;并且这种实例方式也比原生的 Python 实现在性能上要好。
最后
pwd 还有一个兄弟模块叫 grp ,实现上和 pwd 是一样的。想到如果我下周用 grp 再水一篇,一来我会不好意思,二来也无聊,还不如聊宏观经济,吹吹水来的开心,所以这周更新两个模块。