# 关于主机

# import os

:Python 的标准库,用于调用本机操作系统的 API 。

# 关于进程

  • 查看进程的信息:

    >>> import os
    >>> os.geteuid()  # 返回当前进程的 uid
    0
    >>> os.getlogin() # 返回当前终端登录的用户名
    'root'
    >>> os.getgid()   # 返回 user group id
    0
    >>> os.getpid()   # 返回当前进程的 pid
    18516
    >>> os.getppid()  # 返回 ppid ,也就是父进程的 pid
    6484
    >>> os.ctermid()  # 返回当前进程的终端文件(类 Unix 系统才支持该功能)
    '/dev/tty'
    
  • 关于环境变量:

    >>> os.environ    # 它存储了当前进程的所有终端环境变量,取值为 Map 类型
    environ({...})
    >>> os.environ.get('PATH')        # 返回名为 'PATH' 的环境变量
    'C:\\Windows\\system32;C:\\Windows;C:\\Windows\\System32\\Wbem;...
    >>> os.environ['DEBUG'] = 'true'  # 可以修改环境变量,不过只会作用于当前进程
    
  • 关于工作目录:

    >>> os.getcwd()       # 返回当前进程的工作目录
    'C:\\Users\\Leo'
    >>> os.chdir('D:\\')  # 将工作目录,改成指定目录
    

# os.system()

os.system(cmd)
  • 功能:创建一个终端(属于当前进程的子进程),执行一条命令。等子进程执行结束之后,将子进程的返回码(取值为 int 类型),作为该函数的返回值。
  • 例:
    >>> r = os.system('echo hello')
    hello   # 子进程的 stdout、stderr 会输出到当前进程的终端
    >>> r   # 子进程的返回码
    0
    

# os.popen()

os.popen(cmd, mode='r', buffering=-1)
  • 功能:创建一个终端(属于当前进程的子进程),执行一条命令。该函数返回一个管道(pipe),用于读取子进程的 stdout 。

    • 子进程的 stderr 会输出到当前进程的终端。
    • 参数 mode、buffering 的作用,与 open() 函数相同。
    • 实际上,os.popen() 是对 subprocess.Popen() 的封装。建议使用后者,功能更多。
  • os.system() 会阻塞当前进程,直到子进程运行结束。而 os.popen() 会让子进程、当前进程同时运行。

    >>> p = os.popen('ping localhost -c 3')   # 创建子进程,并开始运行
    >>> p
    <os._wrap_close object at 0x7fedc29ba470>
    >>> p.read()  # 读取子进程的 stdout 。如果子进程尚未结束,则会阻塞当前进程,直到子进程结束
    'PING localhost.localdomain (127.0.0.1) ...'
    

# 关于路径

  • 转换路径:

    >>> os.path.sep   # 返回本机的路径分隔符。Windows 系统通常是 '\\' ,类 Unix 系统通常是 '/'
    '\\'
    >>> os.path.normpath('/tmp/f1/')    # 将一个 path 正常化(并不会判断该路径是否存在),比如转换成本机的路径分隔符
    '\\tmp\\f1'
    >>> os.path.normpath('/tmp//f1//')  # 比如去掉多余的路径分隔符
    '\\tmp\\f1'
    >>> os.path.normpath('')            # 如果输入的 path 为空字符串,则返回 '.'
    '.'
    
    >>> os.path.abspath('.')                # 输入一个 path ,将它转换成绝对路径
    'C:\\Users\\Leo'
    >>> os.path.relpath('/tmp/f1', '/tmp')  # 返回第一个 path ,相对于第二个 path ,的相对路径
    'f1'
    >>> os.path.relpath('/tmp/f1', '/tmp/test/f2')
    '..\\..\\f1'
    
  • 分割路径:

    >>> os.path.split('/tmp/1.py')  # 输入一个 path ,将它分割成目录名和文件名
    ('/tmp', '1.py')
    >>> os.path.split('/tmp/')      # 最后一个路径分隔符的右侧内容,会被视为文件名
    ('/tmp', '')
    >>> os.path.split('')
    ('', '')
    >>> os.path.normpath('C:/1/2.py').split(os.path.sep)  # 也可手动分割 path 这个字符串
    ['C:', '1', '2.py']
    
    >>> os.path.dirname('/tmp/1.py')    # 提取目录名
    '/tmp'
    >>> os.path.basename('/tmp/1.py')   # 提取文件名
    '1.py'
    >>> os.path.join('/tmp', '1.py')    # 用本机的路径分隔符,将目录名、文件名合成一个 path
    '/tmp\\1.py'
    >>> os.path.join('/tmp', 'test', '1.py')  # 可以输入多层目录,一起合并
    '/tmp\\test\\1.py'
    

# 关于文件

  • 获取文件的信息:

    >>> os.path.exists('C:\\Users')   # 输入一个 path ,判断它是否存在于本机
    True
    >>> os.path.isfile('C:\\Users')   # 判断是否为文件,而不是目录。如果该路径不存在,则也返回 False
    False
    >>> os.path.isdir('C:\\Users')    # 判断是否为目录
    True
    >>> os.path.getsize('C:\\Users')  # 返回文件的体积,单位为 bytes 。如果该路径不存在,则抛出 OSError 异常
    4096
    >>> os.path.getctime('C:\\Users') # 返回文件的创建时间
    1546567973.6038435
    >>> os.path.getatime('C:\\Users') # 返回文件的最后访问时间
    1562806458.460649
    >>> os.path.getmtime('C:\\Users') # 返回文件的最后修改时间
    1562806458.460649
    >>> os.stat('C:\\Users')          # 返回文件的详细信息
    os.stat_result(st_mode=16749, st_ino=1407374883763938, st_dev=2351311628, st_nlink=1, st_uid=0, st_gid=0, st_size=4096, st_atime=1562806458, st_mtime=1562806458, st_ctime=1546567973)
    
  • 修改文件:

    >>> os.link(src, dst)                    # 创建硬链接。如果 dst 路径已存在,则抛出 OSError 异常
    >>> os.symlink(src, dst)                 # 创建符号链接
    >>> os.rename(src, dst)                  # 重命名
    >>> os.remove(path)                      # remove a file or directory
    

# 关于目录

  • 查看指定目录下的所有文件、文件夹:

    >>> os.listdir('D:\\test')
    ['1.py', '__pycache__']
    
    • 返回结果,包括隐藏文件,但不包括 ... 两个特殊文件。
    • 返回结果,不包括子目录下的内容。
    • 如果遇到异常(比如无权访问目标目录),则该函数不会返回任何结果。
  • 查看指定目录以及所有子目录的内容:

    >>> os.walk('.', onerror=print)
    <generator object walk at 0x000001CC520EBA98>
    >>> for i in _:
    >>>     print(i)
    >>>
    ('.', ['__pycache__'], ['1.py'])
    ('.\\__pycache__', [], [])
    
    • 该函数的返回值是一个生成器,迭代的每个元素是一个三元组:
      • 目录名
      • 该目录下的文件夹列表
      • 该目录下的文件名列表
    • 如果遇到异常,则该函数默认会忽略异常。建议传入 onerror 参数,记录遇到的异常。
  • 修改目录:

    >>> os.mkdir(path)                       # 创建目录。如果该路径已存在,则抛出 OSError 异常
    >>> os.makedirs('1/2/3')                 # 创建目录。如果中间几层目录不存在,则自动创建它们。如果最终目录已存在,则抛出 OSError 异常
    >>> os.makedirs('1/2/3', exist_ok=True)  # 如果最终目录已存在,则不报错
    >>> os.rmdir(path)                       # 删除目录。要求该目录不包含任何文件、子目录。如果该目录的内容不为空,则抛出 OSError 异常
    

# import sys

:Python 的标准库,用于调用 Python 解释器的 API 。

  • 官方文档 (opens new window)

  • 关于当前进程:

    >>> import sys
    >>> sys.argv        # 返回当前进程启动时,传入的命令行参数。不过手动解析 sys.argv 比较麻烦,更推荐使用 argparse 标准库
    ['']
    >>> sys.executable  # 返回当前进程的可执行文件的路径
    '/usr/bin/python3'
    
    >>> sys.exit()      # 退出当前 Python 解释器,也就是终止当前进程。默认返回 0 ,作为当前进程的返回码
    >>> sys.exit(1)     # 返回指定数字
    >>> exit()          # 也可调用内置函数 exit()
    
  • 关于 Python 解释器:

    >>> sys.path        # 记录几个常用目录。执行 import 语句时,会到这些目录下查找文件
    ['', '/usr/lib64/python36.zip', '/usr/lib64/python3.6', ...]
    >>> sys.modules     # 取值为 dict 类型,存储当前加载的所有 Python 模块
    {'sys': <module 'sys' (built-in)>, 'builtins': <module 'builtins' (built-in)>, ...}
    >>> sys.platform    # 返回本机操作系统的类型,比如 linux、darwin、win32
    'linux'
    >>> sys.implementation  # 返回 Python 解释器的版本信息。不过这些信息不多,更推荐使用 platform 模块
    namespace(_multiarch='x86_64-linux-gnu', cache_tag='cpython-36', hexversion=50727152, name='cpython', version=sys.version_info(major=3, minor=6, micro=8, releaselevel='final', serial=0))
    
  • 以下三个对象,表示当前终端的标准输入、输出、错误:

    sys.stdin
    sys.stdout
    sys.stderr
    
    • 例:写入字符串到 stdout
      >>> sys.stdout    # 标准输出的存在,像一个文本文件
      <_io.TextIOWrapper name='<stdout>' mode='w' encoding='utf-8'>
      >>> count = sys.stdout.write('hello')   # 向 stdout 写入一个字符串,然后返回写入的字符数
      hello
      
    • 例:将 stdout、stderr 重定向到一个磁盘文件
      >>> f = open('output.txt', 'w')
      >>> sys.stdout = f
      >>> sys.stderr = f
      >>> print('hello')    # print() 函数会将字符串作为 stdout 输出
      >>> raise RuntimeError('testing...')    # 抛出异常,这会作为 stderr 输出
      >>> sys.__stdout__    # 如果想恢复原来的 stdout ,则可使用该内置变量
      <_io.TextIOWrapper name='<stdout>' mode='w' encoding='utf-8'>
      
  • 关于异常:

    >>> a
    NameError: name 'a' is not defined
    >>> sys.last_type     # 返回最近一个异常的类型
    <class 'NameError'>
    >>> sys.last_value    # 返回最近一个异常的描述
    NameError("name 'a' is not defined",)
    
  • 关于对象:

    >>> sys.getrefcount(object()) # 返回对象的引用计数
    1
    >>> sys.getsizeof(object())   # 返回对象占用的内存大小,单位为 bytes
    50
    

# import platform

:Python 的标准库,用于查看本机的平台信息。

  • 官方文档 (opens new window)

  • 关于操作系统:

    >>> import platform
    >>> platform.uname()      # 返回操作系统的类型、版本等信息
    uname_result(system='Linux', node='CenOS-1', release='3.10.0-1120.51.1.el7.x86_64', version='#1 SMP Tue Jun 28 15:37:28 UTC 2022', machine='x86_64', processor='Intel64 Family 6 Model 158 Stepping 10, GenuineIntel')
    >>> platform.system()     # 返回操作系统的类型,比如 Linux、Darwin、Windows
    'Linux'
    >>> platform.release()    # 返回操作系统的版本
    '3.10.0-1120.51.1.el7.x86_64'
    >>> platform.machine()    # 返回 CPU 的架构类型。比如 x86_64、AMD64
    'x86_64'
    >>> platform.processor()  # 返回 CPU 的具体名称
    'Intel64 Family 6 Model 158 Stepping 10, GenuineIntel'
    
  • 关于 Python 解释器:

    >>> platform.architecture()[0]        # 返回本机的 CPU 字长
    '64bit'
    >>> platform.python_version()         # 返回 Python 解释器的版本
    '3.6.8'
    >>> platform.python_version_tuple()   # 将版本号,分割成三个字段
    ('3', '6', '8')
    >>> platform.python_implementation()  # 返回 Python 解释器的实现类型,比如 CPython、Jython、PyPy
    'CPython'
    

# import psutil

:Python 的第三方库,用于监控本机的运行状态。用途像 Linux 的 ps、free 等命令。

  • 安装:pip install psutil

  • 官方文档 (opens new window)

  • 关于进程:

    >>> import psutil
    >>> psutil.pids()         # 返回本机所有进程的 PID
    [1, 2, 4, 6, 7, 8, 9, 10, ...]
    >>> psutil.pid_exists(1)  # 检查指定 PID 的进程是否存在
    True
    >>> psutil.Process(1)     # 通过 PID 选中一个进程,返回一个 Process 对象。之后可以调用该对象的各个方法
    psutil.Process(pid=1, name='systemd', status='sleeping', started='2022-01-15 16:00:30')
    
    >>> p = psutil.Process(os.getpid()) # 通过 os.getpid() 获取当前进程的 PID ,然后选中当前进程
    >>> p
    psutil.Process(pid=26002, name='python3', status='running', started='16:55:28')
    >>> p.pid
    26002
    >>> p.name()        # 返回进程的名称
    'python3'
    >>> p.status()      # 返回进程的状态
    'running'
    >>> p.create_time() # 返回进程的创建时间,取值为 Unix 时间戳
    1661504128.0
    >>> p.terminate()   # 终止进程
    
    >>> p.exe()         # 返回进程的可执行文件的路径
    '/usr/bin/python3.6'
    >>> p.cmdline()     # 返回进程的启动命令
    ['python3']
    >>> p.cwd()         # 返回进程的工作目录
    '/root'
    >>> p.username()    # 返回启动该进程的用户名
    'root'
    
    >>> p.parent()        # 返回该进程的父进程
    psutil.Process(pid=3889, name='bash', status='sleeping', started='16:28:31')
    >>> p.children()      # 返回该进程的所有子进程
    []
    >>> p.num_threads()   # 返回该进程的线程数
    1
    >>> p.threads()       # 返回该进程的所有线程
    [pthread(id=32123, user_time=0.06, system_time=0.0)]
    
  • 查看进程的状态:

    >>> p.cpu_percent(1)    # 阻塞 1 秒,然后统计这段时间内,该进程的 CPU 使用率
    15.6
    >>> p.memory_info()     # 返回该进程的内存使用信息
    pmem(rss=10549008, vms=174663920, shared=3809280, text=4096, lib=0, data=6295552, dirty=0)
    >>> p.open_files()      # 返回该进程打开的所有文件
    [popenfile(path='/tmp/f1', fd=3, position=0, mode='w', flags=32769), ...]
    >>> p.net_connections() # 返回该进程的所有 Socket 网络连接
    [pconn(fd=115, family=<AddressFamily.AF_INET: 2>, type=<SocketType.SOCK_STREAM: 1>, laddr=addr(ip='10.0.0.1', port=48776), raddr=addr(ip='10.0.0.2', port=80), status='ESTABLISHED'), ...]
    
  • 查看 CPU 的状态:

    >>> psutil.cpu_count()              # 返回本机的 CPU 总核数(默认为逻辑核数)
    8
    >>> psutil.cpu_count(logical=False) # 返回 CPU 物理核数
    4
    >>> psutil.cpu_percent()            # 返回所有 CPU 的平均使用率。统计的时间范围是,从上一次调用该函数开始,到目前为止
    7.2
    >>> psutil.cpu_percent(interval=1, percpu=True) # 阻塞 1 秒,然后统计这段时间的各个CPU使用率
    [20.6, 7.7, 10.8, 20.0, 12.3, 4.6, 10.8, 4.6]
    >>> psutil.cpu_times_percent()      # 查看 CPU 各个维度的使用率(像 Linux 的 top 命令)
    scputimes(user=3.2, system=4.0, idle=92.5, interrupt=0.2, dpc=0.2)
    
  • 查看内存的状态:

    >>> psutil.virtual_memory()   # 返回本机的内存使用量,单位为 bytes(像 Linux 的 free 命令)
    svmem(total=8424906752, available=2264326144, percent=73.1, used=6160580608, free=2264326144)
    >>> psutil.swap_memory()      # 返回本机 swap 分区的使用量
    sswap(total=15404228608, used=9708523520, free=5695705088, percent=63.0, sin=0, sout=0)
    
  • 查看磁盘的状态:

    >>> psutil.disk_partitions()    # 返回本机的所有磁盘分区
    [sdiskpart(device='/dev/vda1', mountpoint='/', fstype='ext4', opts='rw,relatime,data=ordered'), ...]
    >>> psutil.disk_usage('/dev/vda1')  # 查看某个磁盘分区的使用量
    sdiskusage(total=295923871744, used=237350260736, free=58573611008, percent=80.2)
    
  • 查看网络的状态:

    >>> psutil.net_if_addrs()       # 返回本机的所有网卡地址(interface address)
    {'lo': [snicaddr(family=<AddressFamily.AF_INET: 2>, address='127.0.0.1', netmask='255.0.0.0', broadcast=None, ptp=None), ...}
    >>> psutil.net_connections()    # 返回本机所有的 Socket 网络连接
    [sconn(fd=3, family=<AddressFamily.AF_INET: 2>, type=<SocketKind.SOCK_STREAM: 1>, laddr=addr(ip='0.0.0.0', port=22), raddr=(), status='LISTEN', pid=1320), ...]
    >>> psutil.net_connections(kind='tcp')  # 只返回 tcp 类型的 Socket
    [sconn(fd=3, family=<AddressFamily.AF_INET: 2>, type=<SocketKind.SOCK_STREAM: 1>, laddr=addr(ip='0.0.0.0', port=22), raddr=(), status='LISTEN', pid=1320), ...]