引言:再谈为什么强调编程理念与基础
相信对过笔者关于Python系列的历史文章,会发现,其实始终存在一种理念贯穿其中:先在脑海中构建编程的核心理念框架,然后在实用中不断补全语言的基础,从来不追求语言语法的大而全的堆砌。
编程的核心理念,一以贯之,始终是围绕着数据的表达及数据的处理,分别抽象出数据结构与函数/算法,刚好对应了计算机本科的一门核心基础课程:《数据结构与算法》。数据结构与算法的分离还是封装,对应了两个流派:面向过程和面向对象。
我们之所以不堆砌Python中大而全的语法,一方面是因为Python讲语法的书普天盖的到处都是,随便找一本作为工具书能够速查,或者使用ChatGPT现用现查都是可以的。强行背下来无益,反而可能记错、遗忘。能放到外存中的没必要放到我们大脑这个内存区域的,就没必要硬往里塞了。
之所以反复介绍一些Python中朴实无华的基础,类似于武侠小说中的武学修行过程,一套罗汉拳在扫地僧手里也能有出神入化的效果,真正的高手追求的首先都是打基础,基础扎实后,遇到实际应用场景,摘花飞叶,信手拈来,皆可以极简之道达成预期效果。
废话到此,本篇文章继续来聊Python中的基础:Python中一个很容易被忽视,却又挺实用的模块:sys模块。
脚本接收参数
前面文章中,我们基本都是在代码中写死了,脚本每次执行,除了随机模块外,输出基本都是一致的,我们怎么能够让脚本能根据一些参数,从而得到不一样的结果呢。
比如,通过指定参数,来让脚本生成指定条测试数据;
又比如,通过指定参数,来让脚本能够分别以测试环境或者生产环境的配置来运行。
Python中的sys模块,让我们的脚本可以轻松实现接收脚本执行的参数,从而基于参数进行后续的处理,直接上代码:
import sys
print(len(sys.argv))
print(type(sys.argv))
print(sys.argv)
如果通过以下命令执行脚本:
python3 ./sys_test.py
输出结果:
如果我们通过以下命令执行脚本呢:
python3 ./sys_test.py 10 100
输出结果:
由上可知:
1、可以通过sys.argv获取到执行传递的参数
2、sys.argv是一个list结构,按顺序存放所有的参数
3、sys.argv[0]存放的是脚本文件名称(含路径),用户自定义的参数从sys.argv[1]开始
基于用户参数来判断环境配置的示例:
import sys
env = 'dev'
cnt_data = 100
if len(sys.argv) > 1:
env = sys.argv[1]
if len(sys.argv) > 2:
cnt_data = int(sys.argv[2])
print(f"当前在{'开发环境' if env == 'dev' else '生产环境'}")
print(f"计划生成{cnt_data}条测试数据")
按照如下命令,不传参:
python3 ./sys_test.py
输出结果:
传参重新执行:
python3 ./sys_test.py prod 20000
输出结果:
控制脚本提前结束
有时候,我们在做了一些校验之后,发现需要提前终止脚本的运行,这时候,可以使用sys.exit()函数,来提前终结脚本的运行。
首先看一下sys.exit()函数的定义:
由以上定义,可知:
1、sys.exit()函数不传任何参数,或者传入一个整数0,表示是正常结束;
2、传递非0的整数,表示异常结束,通常根据传递的整数,来标识结束的原因;
3、如果传入一个字符串,则表示异常结束,该字符串会被自动输出,通常字符串为异常结束的原因。
比如,我们要求脚本执行时必须指定执行环境和测试数据行数,否则就异常终止并提示:
import sys
# 假如我们要求脚本执行必须传参,来确定执行环境和测试数据条数
if len(sys.argv) < 3:
sys.exit('参数异常:需要指定执行环境和数据条数')
env = sys.argv[1]
cnt_data = int(sys.argv[2])
print(f"当前在{'开发环境' if env == 'dev' else '生产环境'}")
print(f"计划生成{cnt_data}条测试数据")
如果不传参数直接执行,则脚本提前结束,输出结果为:
获取标准流
这部分的内容,其实在前面关于print()函数的使用的文章中,已经涉及,这里再略微述及一下,不再展开:
import sys
# 通过标准输入流,从终端读取用户输入的数据
# 脚本执行后,会阻塞等待用户输入,需要在终端输入一行,然后回车,才会继续执行
# python中input()函数,底层也是通过sys.stdin来实现的
s1 = sys.stdin.readline()
# 将s1通过标准输出流输出,也就是print()函数的默认操作
sys.stdout.write(s1)
# 将s1通过标准错误输出流输出
sys.stderr.write(s1)
注意,该脚本执行时,会阻塞等待用户输入,直到输入一行并回车后,才会继续向下执行。程序输出结果:
sys模块获取环境信息
有时候,我们编写的脚本,可能对Python的版本、操作系统有特殊要求,所以,需要获取并检测这些信息。
如同操作系统在执行命令时,会通过系统环境变量path中配置的路径进行查找,Python中查找导入的模块时,也是通过类似的path路径来查找的。
以上,这些信息都能在sys模块中获取到:
import sys
# 通过sys模块,获取系统环境信息
# 获取Python版本号
print(sys.version)
# 获取Python版本的信息描述
print(sys.version_info)
# 获取脚本执行的操作系统类型:
print(sys.platform)
# 获取脚本执行时的模块搜索路径
print(sys.path)
# 获取python对应的路径
print(sys.executable)
在笔者的系统中的执行结果:
关于sys.platform的输出,通常有以下几种取值:
- darwin:所有版本的MacOS;
- win32:大部分的32位和64位的Windows系统;
- linux:大多数的Linux发行版;
- 其他比较少见,比如openbsd、os2、riscos等
获取Python对象相关信息
在Python中,一切皆对象。我们可以通过sys模块,查看对象的相关信息,以便更清晰的理解一些实际的运行细节。
import sys
# 通过sys模块,获取对象相关信息
# 获取Python可以创建的最大整数
print(sys.maxsize)
# 获取Python中浮点数对象的相关信息
print(sys.float_info)
# 获取对象的引用计数(内存垃圾回收的一个因素),以及对象的大小
a = (1, 2, 3)
b = a
print(sys.getrefcount(a))
print(sys.getsizeof(a))
程序输出结果:
总结
Python的sys模块提供了许多关于Python虚拟机、运行环境相关的很实用的功能,我们可以更加方便地访问和控制运行时环境。
本文中的关于sys模块的内容,只是笔者整理的在实用中可能更加常用的功能,对sys模块感兴趣的,可以查看sys相关官方文档学习掌握更多的内容。