python系统编程
系统编程
系统工具
概述
python系统模块:
模块名 | 作用 |
---|---|
*sys | 负责导出与怕以后呢解释器本身相关的组件 |
*os | 包含与python所在底层操作系统相应的变量和函数 |
*os.path | 为文件和目录处理工具提供了可移植的接口 |
glob | 用于文件名扩展 |
socket | 用于网络连接和进程间通信 |
threading,_thread,queue | 用于运行和同步化并发线程 |
subprocess,multiprocessing | 用于启动和控制并行进程 |
signal,select,shutil,tempfile | 用于多种系统相关任务 |
第三方扩展 | 以下 |
pySerial | 串行端口接口 |
Pexpect | 用于控制程序间对话 |
Twisted | 网络框架 |
获取模块文档:
-
获取属性:dir()
-
获取用法:
__doc__
或help()
sys模块
工具 | 作用 |
---|---|
*sys.platform | 底层操作系统名称 |
sys.maxsize | 当前计算机可容纳的最大整型 |
sys.version | python解释器版本号 |
*sys.path | 正在运行的python解释器真正的模块搜索路径 |
包含代表脚本主目录的指示器(首项),交互模式下是空字符串 | |
可以更改,并不是永久性的 | |
*sys.modules | 字典,python进程所导入的每一个模块 |
sys.getrefcount | 查看对象的引用次数 |
sys.builtin_module_names | python可执行程序的内置模块名称 |
sys.exc_info() | 元祖,最近异常的类型,值,追踪对象 |
追踪对象可用模块traceback处理 | |
将追踪对象传入traceback.print_tb() | |
sys.argv | 命令行参数 |
stdin,stdout,stdrrr | 标准流 |
sys.exit | 强制退出 |
os模块
提供了POSIX(可移植操作系统接口)工具,不依赖平台的目录处理,os.path
常用的os工具:
任务 | 工具 |
---|---|
shell变量 | os.environ:设置和获取shell环境变量 |
运行程序 | os.execv |
os.execlp:启动新程序 | |
os.spawnv:启动带有底层控制的新程序 | |
os.system():在pythin脚本中运行shell命令,会暂停它的调用者,可在命令后加& | |
os.popen():运行shell命令并与其输入流(传入’w’参数,write()方法)或输出流(默认,read()方法)相连接. | |
os.startfile():用相应的软件打开文件,无论文件是什么 | |
派生程序 | os.waitpid,os.kill |
os.fork:在类Unix系统下派生新的子进程 | |
os.pipe:负责进程间通信 | |
文件描述符,文件锁 | os.resd,os.write |
os.open:打开基于底层描述符的文件 | |
os.stat:获取文件底层信息 | |
文件处理 | os.rename,os.rmdir |
os.walk:将函数和循环运用与整个目录树的各部分 | |
os.remove:根据路径名删除文件 | |
os.mkdir:创建新目录 | |
os.mkfifo:创建新的命名管道 | |
管理工具:提供信息,帮助管理 | os.chmod,os.listdir,os.access |
os.getpid():给出掉用函数的进程的id | |
os.getcwd():返回当前目录 | |
os.chdir():改变目录 | |
移植工具 | os.path.split(‘path’):将路径分割为目录和文件 |
os.path.splitext(‘path’):分割了文件的扩展名 | |
os.path.normpath(‘path’:将路径分隔符统一为平台的目录分隔符) | |
os.path.abspath(‘path’):返回文件的完整目录路径名.如添加前缀和处理…语法 | |
os.path.join:将目录和文件合成路径 | |
os.path.dirname(‘path’)/basename(‘path’):返回目录/文件 | |
os.sep:目录分割符号 | |
os.pathsep:目录列表中分隔目录的符号 | |
os.pardir:父目录 | |
os.curdir:当前目录 | |
os.linesep:换行符 | |
路径名工具 | os.path.getsize(‘path’):通过文件名获取文件大小 |
os.path.isdir(‘path’)/isfile(‘path’):检测文件类型,是目录/文件 | |
os.path.exists(‘path’):测试文件是否存在 |
脚本运行上下文
当前工作路径
当前工作路径(CWD)与脚本所在路径区别:
- 当前工作路径(CWD):
- 当前工作路径是启动脚本的路径,即输入命令行的地方.
- 脚本中没有路径的文件名将会映射到此.
- 通过os.getcwd()获得,os.chdir()改变.
- 当通过图标执行一个脚本时,cwd会被设置为脚本所在路径.
- 脚本所在路径:
- 脚本所在路径是脚本文件物理存储位置.
- import导入时,最先搜索的目录.
- 可以通过sys.path列表中的首项看到.
命令行参数
sys.argv:得到命令行参数列表.sys.argv[0]为执行脚本的名称,在命令行出现的顺序决定列表中的索引
python中的命令行处理工具解析更复杂的命令行:
- getopt模块
- optparse模块,功能更强大
note:
unix上的可执行脚本:
脚本第一行#!/usr/bin/env指定解释器
chmod u+x scripname:增加可执行权限
shell环境变量
python通过一个类似python字典的对象os.environ访问环境变量
获取环境变量:
- os.environ[‘环境变量名’],例如获取PYTHONPATH:os.environ[‘PYTHONPATH’]
修改环境变量:
-
通过对os.environ[‘环境变量名’]赋值,在内部调用os.putenv改变环境变量(修改是临时的,只对程序本身和子程序有效)
-
子程序:由Unix下的os.spawnv,os.fork/exec,以及所有平台的os.popen,os.system,subprocess启动的程序
-
修改是临时的原因:一个子程序始终从父程序继承环境变量,而子程序的环境变量不会传递给父进程.
-
标准流
标准流是预先打开的文件对象,python启动时被绑定到控制台窗口,sys模块提供了标准输入(sys.stdin),标准输出(sys.stdout)和错误流(sys.stderr)
重定向流到文件或程序(依赖shell命令行):
-
标准输入流重定向到文件输入:
< fielname
-
标准输出流重定向到文件:
>filename
-
结合使用:
< inputfile > outputfile
-
管道,一个程序的标准输出发送到另一个程序的标准输入,python脚本可以在任意一端:
|
重定向流与用户交互:
-
当输入流被重定向后,linux中可以通过/dev/tty文件(当前虚拟终端)读取键盘输入
-
文件的isatty()方法探测文件是否连接到控制台
重定向流到python对象:
-
任何提供了类似文件read方法的对象可以指定给sys.stdin,以从该对象的read方法读取输入
-
任何定义了类似文件write方法的对象可以指定给sys.stdout,所有标准输出将发送到该对象方法上
-
需要保存和重置原来的流
io标准库:
```python
from io import StringIO, BytesIO
# StringIO提供对象,将文件对象接口和内存字符串相映射(文本)
buff = StringIO() # 在字符串中保存写入的文本
buff.write('string\n')
buff.getvalue() # 取出值
buff = StringIO('string\nstream\n') # 从字符串中读取输入值
buff.readline()
# ByteIO提供对象,将文件操作映射到内存字节缓冲区(二进制)
stream = BytesIO() # 在字节缓冲区中保存写入的文本
stream.write(b'stream')
stream.getvalue()
stream = BytesIO(b'stream') # # 从字节缓冲区中读取输入值
stream.read()
```
print调用中的重定向语法:
- print(string, file=filename) #filename为文件名,需要打开的,有写入权限的
subprocess模块:
-
运行命令的替代方案,对流的控制更完善,控制的是子程序的流.
-
subprocess.call(‘cmd’,shell=True),shell与平台相关,类Unix上为真时,由shell执行程序,否则由os.execvp运行
-
将stdout流与管道连接,然后用communicate来运行命令,并接收它的标准输出流和错误流文件
from subprocess import Popen, PIPE pipe = Popen('python hello.py', stdout=PIPE, stdin=PIPE) # 获取派生程序的输出流和输入流 pipe2 = Popen('python reader.py', stdin=pipe.stdout) # 将pipe的输出流给pipe2的输入流 pipe.stdin.write('string') #写入输入流 pipe.stdin.close() # 关闭输入流文件 pipe.stdout.read() # 读取输出流 # pipe.communicate() # # pipe.returncode # 查看退出状态,成功一般是0 pipe.wait() # 退出状态
os.popen:
```python
import os
pipe = os.popen('python hello_out.py') # 默认对stdout读
pipe.read()
print(pipe.close()) # None代表没有错误
pipe = os.popen('python hello_in.py', 'w') # 对stdin写
pipe.write('Gumby')
pipe.close()
```
文件和目录工具
文件工具
内建文件对象
-
支持多种方法:将缓冲区写入磁盘(‘flush’),释放系统资源( ‘close’),获取底层文件句柄(‘fileno’),读取数据(‘read’, ‘readline’, ‘readlines’),移动到文件的任意位置(‘seek’),返回当前位置(‘tell’),写入数据(‘writable’, ‘write’, ‘writelines’)
-
open(file, mode='r', buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None)
-
file:文件名,也可以是文件描述符
-
mode:r可读(默认);w可写,并擦除以前任何内容;a追加;+可读可写;b以二进制方式打开
-
buffering:0无缓存,二进制模式;1逐行缓冲;其他全缓冲(默认)
-
encoding:编码设置
-
-
seek(N, whence=0)
-
0:绝对的开始位置,偏移量非负
-
1:相对前位置,偏移量可正可负
-
2:绝对的末尾位置,偏移量一般为负
-
用struct模块解析打包的二进制数据:
import struct # 导入包
data = struct.pack('>i4shf', 2, 'spam', 3, 1.234) # 按照特定格式打包,>表示高位优先,i是四字节整数,4s代表四字节字符串,h是二字节整数,f是浮点数
value = struct.unpack('>i4shf', data) # 按照同样的格式解包
os模块中的底层文件工具
-
os.open(path, flags, mode):打开文件并返回其描述符.描述符是整数代码或句柄,用来标识文件,mode是模式标识符,提供更多的底层控制.
-
O_EXCL:唯一访问权
-
O_NONBLOCK:非阻塞模式
-
(os.O_RDWR|os.O_BINARY):相当与rb+
-
-
os.read(descriptor, N):最多读取N个字节并返回一个字节字符串,descriptor是描述符.
-
os.write(descriptor, string):把字节字符串string中的字节写入文件.
-
os.lseek(descriptor, position, how):在文件中移至position,how相当与seek中的模式.
-
os.fdopen(descriptor, ‘rb’):将文件描述符封装成文件对象,第二个参数是文件对象模式
-
其他os模块文件工具
-
os.chmod(filepath, Ooxxx):更改文件权限.文件路径和三位八进制(与Unix下文件设置相同)
-
os.renaem(oldname, newname):更改名称
-
os.remove(filename):删除文件
-
os.stat:(fielname):文件的底层信息
目录工具
遍历目录
-
os.popen():运行shell列表命令,例如unix中ls,windows中dir.与命令耦合,不跨平台
-
glob.glob()模块:接受路径文件名(每一级路径都可以)模式扩展(?单个字符,*任意个字符,[]字符选集),返回一个匹配文件名(带前缀路径)组成的列表.
-
os.listdir():接受路径目录名,返回该目录下所有文件名(不带路径前缀)列表.
-
golb和walk都都通过调用listdir实现.
-
如果文件名有特殊字符,可以通过传入字节字符串(b’…').
-
文件名编码:os.getfilesystemencoding()
-
遍历目录树
- os.walk():接受一个路径目录名,返回一个生成器,为该目录及其每一个递归子目录下产生一个包括(当前目录名称,子目录列表,文件列表)的三元组.用topdown=False参数可以自底向上遍历.删除返回的元祖里子目录列表中的名称,可以对目录树的枝干进行修剪.
并行系统工具
进程分支
os.fork():
-
启动新的并行子进程(内存中原来进程的一个副本),在子进程中返回0,在父进程中返回pid
-
os.getpid()获得当前进程的pid
-
全局对象在子进程开始是有相同的值,全局内存是被复制而不是共享,只改变自己的副本.
-
子进程可以通过显是的调用os._exit(0)退出
fork和exec组合:
-
os.execlp():用一个全新的程序覆盖执行原来的程序,通过fork启动子进程再exec覆盖,开启一个与原程序并行运行的新程序,但pid不变
-
exec系列:
-
execv(program, commandlinesequence):参数为可执行程序的名称(完整路径),命令行参数字符串组成的列表或元组(在shell中输入的命令)
-
execl(program, argv0, argv1, …, argvN):参数形式传入命令行参数
-
excelp,excevp:用系统搜索路径定位可执行程序(不需要完整路径)
-
execve,execle:在最后添加一个字典参数,包含发送给程序的shell环境变量
-
execvpe,execlpe:使用搜索路径并且接受shell环境变量字典参数
-
例子:
os.execlp('python', 'python', 'child.py', str(parm))
-
线程
在同一个进程中,和程序的其他部分并行的调用函数(或其他可调用对象),常用于非阻塞的输入调用和GUI中长时间的任务.
特点:
-
相对与分支进程开销小,进程适合计算密集型操作,线程适合IO密集型操作
-
共享全局内存(对象和命名空间4),要仔细控制共享项目的访问权
-
全局解释器锁(GIL):同一时间只有一个线程运行python代码,不能利用多核
_thread模块:
-
_thread.start_new_thread():
-
开始一个新线程,接受一个函数(或其他可调用对象,如lambda函数,对象方法)和一个参数元组,返回一个无用值.
-
线程在其运行的函数返回后退出,或主线程退出后随之退出.
-
线程出现异常不影响程序其他部分的运行.
-
-
同步访问共享对象和名称:
-
锁:要修改一个共享对象,线程 需要获得一把锁,然后修改,之后释放锁给其他线程获取.确保任何时间只有一个线程持有锁.
-
_thread.allocate_lock():创建全局锁对象,_thread.exit():线程退出
-
全局锁对象的acquire()方法获取锁,release()方法释放锁,之间是需要互斥的操作
-
locked()方法检测锁是否被获取,被获取返回true
-
-
等待派生线程退出(线程通信)
-
锁列表:创建一个锁列表,通过为每一个子线程结尾获取一把锁,判断每一把锁是否都被获取,则说明子线程都已经结束,就可以退出主线程.
-
整数列表:创建一个列表,每一个子线程结尾都改变其值,通过判断是否每一个值都改变了,得知子线程是否都结束.可在主线程中用time.sleep()暂停等待子线程结束
-
-
上下文管理
- with mutex(全局锁对象):自动上锁和解锁
threading模块:
-
基于对象和类的较高层面的接口,内部使用_thread实现
-
可以通过继承threading.Thread对象定制带有状态(初始化方法)和run()行为(提供线程逻辑业务)的线程类.
-
threading.Lock():创建全局锁对象.全局锁对象的acquire()方法获取锁,release()方法释放锁,之间是需要互斥的操作
-
线程类对象的start()方法:在线程中运行run方法.join():等待直到线程退出.如果任何一个派生线程(守护线程除外)还在运行中,程序不会退出.线程类对象的daemon属性=True可设为守护线程
-
threading.Thread对象接受传给target参数的调用对象和任意传给args参数(默认(),代表无)
-
threading模块还有Semaphore, Condition和Event等
queue模块:
-
线程程序由一系列消费者程序和一系列生产者程序组成,通过将数据存入一个共享的队列或从中取出来进行通信,保证线程安全.队列同步化的是数据传递,某些操作仍然需要为其他目的而使用锁.
-
queue.Queue(maxsize = 0)创建一个队列对象.maxsize可限制队列大小,默认无限制.
-
queue.LifoQueue(maxsize = 0)创建一个栈队列对象
-
queue.PriorityQueue(maxsize = 0)创建一个优先级队列.典型加入的元素是一个元祖(优先级, 数据),优先级数越小,级别越高
-
queue.deque(maxsize = 0)创建一个双线队列
-
queue.empty异常,queue.Full异常:队列空取,队列满存产生的异常
-
队列对象(例如Queue)的put(item, block=True, timeout=None)方法向队列中存入数据.如果满,blocking = False 直接报 Full异常。如果blocking = True,就是等一会,timeout必须为 0 或正数。None为一直等下去,0为不等,正数n为等待n秒还不能存入,报Full异常
-
Queue.get()方法从队列中取出数据,参数类似put
-
Queue.empty(),Queue.full():判断队列是否为空,为满
-
Queue.task_done():表示队列中某个元素被消费进程使用,消费结束发送的信息
-
Queue.join():一直阻塞直到队列中的所有元素都被取出和执行
GUI与线程:
- GUI程序一般采用主GUI线程加一到多个长时间运行的生产者线程,主线程更新界面,每个生产者线程执行一个长时间任务.所有线程共享一个队列,非GUI线程显示结果,GUI线程消耗它们.