学习sys模块

Last Updated: 2023-09-28 00:29:41 Thursday

-- TOC --

本文总结Python标准库中的sys模块所涉及的知识点,这里的sys指Python系统。

sys.exit接口

sys模块的exit函数,通过抛出一个SystemExit异常来尝试结束程序,Python代码可以捕获这个异常来进行一些程序退出前的清理工作,既然可以捕获这个异常,也就可以不退出程序。sys.exit函数同样可以带一个参数来作为程序的退出码,默认是0。

>>> import sys
>>> try:
...     sys.exit(101)
... except SystemExit as e:
...     print(repr(e))
...     print(str(e))
...
SystemExit(101)
101
>>>

捕获了sys.exit()函数抛出的异常,处理之后,还要程序继续退出,可以直接使用exit或quit函数。实践中,完整的使用sys.exit函数的逻辑应该是如下这样的代码:

import sys

def main():
    sys.exit(123)
    return

if __name__ == '__main__':
    try:
        main()
    except SystemExit as e:
        if str(e) == '123':
            print('---123---')
            exit(123)

exit和quit接口

这两个接口一般在交互式环境下使用。它们也会抛出SystemExit异常:

>>> try:
...   exit(123)
... except BaseException as e:
...   print(str(e))
...
123
>>> try:
...   quit(234)
... except SystemExit as e:
...   print(str(e))
...
234

用Exception不能捕获SystemExit异常 ,要使用BaseException,或者直接SystemExit。

os._exit接口

这个函数简单粗暴,就是直接退出python解释器,后面的代码都不执行了!一般程序不推荐使用这种退出方式。

在线程中退出

在python线程中,使用sys.exit(包括exit和quit),都只能实现退出子线程,而不能退出主线程。如果在子线程中调用os._exit,可以实现整个进程的退出。

sys.executable

常常在Windows系统找不到Python安装位置,打印这个变量即可。

C:\Users\xinli>python -c "import sys;print(sys.executable)"
C:\Users\xinli\AppData\Local\Programs\Python\Python37\python.exe

Windows下的where命令

D:\temp>where python
C:\Users\Administrator\AppData\Local\Programs\Python\Python38\python.exe
C:\Users\Administrator\AppData\Local\Programs\Python\Python39\python.exe
C:\Users\Administrator\AppData\Local\Microsoft\WindowsApps\python.exe

sys.setswitchinterval

sys模块下有一对函数,getswitchinterval和setswitchinterval,用来获取和修改python线程的切换间隔。后来在网上查了一下,资料极少。比较有价值的是这篇帖子:https://stackoverflow.com/questions/7376776/sys-setswitchinterval-in-python-3-2-and-beyond

其中有Tim Peter的一句话,说99%的人都不需要用到修改默认的switch interval。

补充一下,通过sys.getswitchinterval,可以得知python3系统默认的线程切换间隔是5毫秒

GIL的存在使得多Python线程不能利用多核CPU并行执行!5毫秒强制切换线程,具体哪个线程能够被执行,还要靠OS调度。

sys.getsizeof

得到Python对象的字节大小!

>>>import sys
>>> sys.getsizeof([1,2,3,4,5,6])
112
>>> sys.getsizeof((1,2,3,4,5,6))
96
>>> sys.getsizeof('123456')
55
>>> sys.getsizeof(123456)
28
>>> sys.getsizeof(1.23456)
24

list对象比tuple更消耗内存。

>>> d = {'1':1,'2':2,'3':3,'4':4,'5':5,'6':6}
>>> sys.getsizeof(d)
368
>>> s = set((1,2,3,4,5,6))
>>> s
{1, 2, 3, 4, 5, 6}
>>> sys.getsizeof(s)
736

看起来set对象比dict对象还要占内存,同样存放6条记录,set对象占用内存是dict的一倍。但它们都比list还要多。所以,如果你的python程序占用内存太多,能用tuple的地方,就别用list!

还有,可以考虑使用generator来减少内存占用。

>>> a = [x for x in range(100)]
>>> sys.getsizeof(a)
912
>>> b = (x for x in range(100))
>>> sys.getsizeof(b)
120

sys.byteorder

得到当前系统的默认字节序。

>>> import sys
>>> sys.byteorder
'little'

C语言判断字节序

sys.getrefcount

Python中都是对象,变量都是对象的引用,这有点像C语言的指针。sys模块指的是Python这个系统,sys.getrefcount接口可以查询解释器内对象的引用计数。当对象的引用计数为0时,Python会自动收回这个对象所占用的内存空间。

sys.getrefcount返回的计数,总是比实际多1,因为包含了调用此函数的临时计数。

>>> import sys
>>> a = 1
>>> sys.getrefcount(a)
1080
>>> b = a
>>> sys.getrefcount(a)
1081
>>> c = [1,2,3]
>>> sys.getrefcount(c)
2
>>> d = c
>>> sys.getrefcount(c)
3
>>> del d
>>> sys.getrefcount(c)
2

1的引用计数好多,python系统内部很多地方都在使用1。

del语句会让引用计数减少。

默认在对应引用计数为0的时候,python内部的垃圾回收机制会将此对象所占用的内存收回。

sys.path

import会优先查找当前目录!文件名一定不要和要import的模块相同,比如不要定义test.py。

Python解释器的包搜索路径。

>>> from pprint import pprint
>>> import sys
>>> pprint(sys.path)
['',
 '/usr/local/python3.8.6/lib/python38.zip',
 '/usr/local/python3.8.6/lib/python3.8',
 '/usr/local/python3.8.6/lib/python3.8/lib-dynload',
 '/home/xinlin/.local/lib/python3.8/site-packages',
 '/usr/local/python3.8.6/lib/python3.8/site-packages']
$ python3 -c 'print("\n".join((__import__("sys").path)))'

/usr/local/python3.8.6/lib/python38.zip
/usr/local/python3.8.6/lib/python3.8
/usr/local/python3.8.6/lib/python3.8/lib-dynload
/home/xinlin/.local/lib/python3.8/site-packages
/usr/local/python3.8.6/lib/python3.8/site-packages
$ python3 -m site
sys.path = [
    '/home/xinlin/repos',
    '/usr/local/python3.8.6/lib/python38.zip',
    '/usr/local/python3.8.6/lib/python3.8',
    '/usr/local/python3.8.6/lib/python3.8/lib-dynload',
    '/home/xinlin/.local/lib/python3.8/site-packages',
    '/usr/local/python3.8.6/lib/python3.8/site-packages',
]
USER_BASE: '/home/xinlin/.local' (exists)
USER_SITE: '/home/xinlin/.local/lib/python3.8/site-packages' (exists)
ENABLE_USER_SITE: True

sys.path的初始值会受到PYTHONPATH、PYTHONHOME等环境变量的影响。可以在脚本运行过程中动态修改sys.path从而import自己需要的模块。

sys.platform

可以用来判断当前Python运行的底层OS系统:

 >>> sys.platform
'linux'
>>> sys.platform
'win32'

platform

更好更准确的判断底层OS系统的方式,是使用标准的platform库:

>>> import platform
>>> platform.system()
'Windows'
>>> import platform
>>> platform.system()
'Linux'

据说使用platform方法可以返回当前操作系统的类型,Windows?Linux?OS X?Unix?FreeBSD?它能比较详细的区分。(其他的一般只能识别Windows和非Windwos)

recursion limit

通过sys模块的两个接口,可以控制Python解释器递归的深度。

>>> sys.getrecursionlimit()
1000
>>> sys.setrecursionlimit(200)
>>> sys.getrecursionlimit()
200

一般不用修改这个值,在调试自己的递归代码时,可以尝试修改,以方便调试。

最大整数

Python系统中的int整数,并不是无限大,而是有一个很大的长度限制,最小是640数字位(640个十进制的数字)。想想64bit的整数最大才长度才20个数字位。这个限制可以通过sys模块修改:

>>> sys.get_int_max_str_digits()
4300
>>> sys.set_int_max_str_digits(640)
>>> int('9'*640)
999999999999999.....
>>> int('9'*641)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: Exceeds the limit (640) for integer string conversion: value has 641 digits; use sys.set_int_max_str_digits() to increase the limit

本文链接:https://cs.pynote.net/sf/python/202206031/

-- EOF --

-- MORE --