python 第七章 模块
2021-07-08 23:05
1 #Popen它的构造函数如下: 2 3 subprocess.Popen(args, bufsize=0, executable=None, stdin=None, stdout=None,stderr=None, preexec_fn=None, close_fds=False, shell=False,
cwd=None, env=None, universal_newlines=False, startupinfo=None, creationflags=0) 4 5 # 参数args可以是字符串或者序列类型(如:list,元组),用于指定进程的可执行文件及其参数。 6 # 如果是序列类型,第一个元素通常是可执行文件的路径。我们也可以显式的使用executeable参 7 # 数来指定可执行文件的路径。在windows操作系统上,Popen通过调用CreateProcess()来创 8 # 建子进程,CreateProcess接收一个字符串参数,如果args是序列类型,系统将会通过 9 # list2cmdline()函数将序列类型转换为字符串。 10 # 11 # 12 # 参数bufsize:指定缓冲。我到现在还不清楚这个参数的具体含义,望各个大牛指点。 13 # 14 # 参数executable用于指定可执行程序。一般情况下我们通过args参数来设置所要运行的程序。如 15 # 果将参数shell设为True,executable将指定程序使用的shell。在windows平台下,默认的 16 # shell由COMSPEC环境变量来指定。 17 # 18 # 参数stdin, stdout, stderr分别表示程序的标准输入、输出、错误句柄。他们可以是PIPE, 19 # 文件描述符或文件对象,也可以设置为None,表示从父进程继承。 20 # 21 # 参数preexec_fn只在Unix平台下有效,用于指定一个可执行对象(callable object),它将 22 # 在子进程运行之前被调用。 23 # 24 # 参数Close_sfs:在windows平台下,如果close_fds被设置为True,则新创建的子进程将不会 25 # 继承父进程的输入、输出、错误管道。我们不能将close_fds设置为True同时重定向子进程的标准 26 # 输入、输出与错误(stdin, stdout, stderr)。 27 # 28 # 如果参数shell设为true,程序将通过shell来执行。 29 # 30 # 参数cwd用于设置子进程的当前目录。 31 # 32 # 参数env是字典类型,用于指定子进程的环境变量。如果env = None,子进程的环境变量将从父 33 # 进程中继承。 34 # 35 # 参数Universal_newlines:不同操作系统下,文本的换行符是不一样的。如:windows下 36 # 用’/r/n’表示换,而Linux下用’/n’。如果将此参数设置为True,Python统一把这些换行符当 37 # 作’/n’来处理。 38 # 39 # 参数startupinfo与createionflags只在windows下用效,它们将被传递给底层的 40 # CreateProcess()函数,用于设置子进程的一些属性,如:主窗口的外观,进程的优先级等等。
简单命令:
1 import subprocess 2 3 a=subprocess.Popen(‘ls‘)# 创建一个新的进程,与主进程不同步 4 5 print(‘>>>>>>>‘,a)#a是Popen的一个实例对象 6 7 ‘‘‘ 8 >>>>>>>9 __init__.py 10 __pycache__ 11 log.py 12 main.py 13 14 ‘‘‘ 15 16 # subprocess.Popen(‘ls -l‘,shell=True) 17 18 # subprocess.Popen([‘ls‘,‘-l‘])
subprocess.PIPE
在创建Popen对象时,subprocess.PIPE可以初始化stdin, stdout或stderr参数。表示与子进程通信的标准流
1 import subprocess 2 3 # subprocess.Popen(‘ls‘) 4 p=subprocess.Popen(‘ls‘,stdout=subprocess.PIPE)#结果跑哪去啦? 5 6 print(p.stdout.read())#这这呢:b‘__pycache__\nhello.py\nok.py\nweb\n‘
这是因为subprocess创建了子进程,结果本在子进程中,if 想要执行结果转到主进程中,就得需要一个管道,即 : stdout=subprocess.PIPE
subprocess.STDOUT
创建Popen对象时,用于初始化stderr参数,表示将错误通过标准输出流输出。
Popen的方法
1 Popen.poll() 2 用于检查子进程是否已经结束。设置并返回returncode属性。 3 4 Popen.wait() 5 等待子进程结束。设置并返回returncode属性。 6 7 Popen.communicate(input=None) 8 与子进程进行交互。向stdin发送数据,或从stdout和stderr中读取数据。可选参数input指定发送到子进程的参数。 Communicate()返回一个元组:(stdoutdata, stderrdata)。注意:如果希望通过进程的stdin向其发送数据,在创建Popen对象的时候,参数stdin必须被设置为PIPE。同样,如 果希望从stdout和stderr获取数据,必须将stdout和stderr设置为PIPE。 9 10 Popen.send_signal(signal) 11 向子进程发送信号。 12 13 Popen.terminate() 14 停止(stop)子进程。在windows平台下,该方法将调用Windows API TerminateProcess()来结束子进程。 15 16 Popen.kill() 17 杀死子进程。 18 19 Popen.stdin 20 如果在创建Popen对象是,参数stdin被设置为PIPE,Popen.stdin将返回一个文件对象用于策子进程发送指令。否则返回None。 21 22 Popen.stdout 23 如果在创建Popen对象是,参数stdout被设置为PIPE,Popen.stdout将返回一个文件对象用于策子进程发送指令。否则返回 None。 24 25 Popen.stderr 26 如果在创建Popen对象是,参数stdout被设置为PIPE,Popen.stdout将返回一个文件对象用于策子进程发送指令。否则返回 None。 27 28 Popen.pid 29 获取子进程的进程ID。 30 31 Popen.returncode 32 获取进程的返回值。如果进程还没有结束,返回None。
supprocess模块的工具函数
1 supprocess模块提供了一些函数,方便我们用于创建进程来实现一些简单的功能。 2 3 subprocess.call(*popenargs, **kwargs) 4 运行命令。该函数将一直等待到子进程运行结束,并返回进程的returncode。如果子进程不需要进行交 互,就可以使用该函数来创建。 5 6 subprocess.check_call(*popenargs, **kwargs) 7 与subprocess.call(*popenargs, **kwargs)功能一样,只是如果子进程返回的returncode不为0的话,将触发CalledProcessError异常。在异常对象中,包 括进程的returncode信息。 8 9 check_output(*popenargs, **kwargs) 10 与call()方法类似,以byte string的方式返回子进程的输出,如果子进程的返回值不是0,它抛出CalledProcessError异常,这个异常中的returncode包含返回码,output属性包含已有的输出。 11 12 getstatusoutput(cmd)/getoutput(cmd) 13 这两个函数仅仅在Unix下可用,它们在shell中执行指定的命令cmd,前者返回(status, output),后者返回output。其中,这里的output包括子进程的stdout和stderr。
1 import subprocess 2 3 #1 4 # subprocess.call(‘ls‘,shell=True) 5 ‘‘‘ 6 hello.py 7 ok.py 8 web 9 ‘‘‘ 10 # data=subprocess.call(‘ls‘,shell=True) 11 # print(data) 12 ‘‘‘ 13 hello.py 14 ok.py 15 web 16 ‘‘‘ 17 18 #2 19 # subprocess.check_call(‘ls‘,shell=True) 20 21 ‘‘‘ 22 hello.py 23 ok.py 24 web 25 ‘‘‘ 26 # data=subprocess.check_call(‘ls‘,shell=True) 27 # print(data) 28 ‘‘‘ 29 hello.py 30 ok.py 31 web 32 ‘‘‘ 33 # 两个函数区别:只是如果子进程返回的returncode不为0的话,将触发CalledProcessError异常 34 35 36 37 #3 38 # subprocess.check_output(‘ls‘)#无结果 39 40 # data=subprocess.check_output(‘ls‘) 41 # print(data) #b‘hello.py\nok.py\nweb\n‘
logging模块 常用命令
一 (简单应用)
1 import logging 2 logging.debug(‘debug message‘) 3 logging.info(‘info message‘) 4 logging.warning(‘warning message‘) 5 logging.error(‘error message‘) 6 logging.critical(‘critical message‘)
输出:
WARNING:root:warning message
ERROR:root:error message
CRITICAL:root:critical message
可见,默认情况下Python的logging模块将日志打印到了标准输出中,且只显示了大于等于WARNING级别的日志,这说明默认的日志级别设置为WARNING(日志级别等级CRITICAL > ERROR > WARNING > INFO > DEBUG > NOTSET),默认的日志格式为日志级别:Logger名称:用户输出消息。
二 灵活配置日志级别,日志格式,输出位置
1 import logging 2 logging.basicConfig(level=logging.DEBUG, 3 format=‘%(asctime)s %(filename)s[line:%(lineno)d] %(levelname)s %(message)s‘, 4 datefmt=‘%a, %d %b %Y %H:%M:%S‘, 5 filename=‘/tmp/test.log‘, 6 filemode=‘w‘) 7 8 logging.debug(‘debug message‘) 9 logging.info(‘info message‘) 10 logging.warning(‘warning message‘) 11 logging.error(‘error message‘) 12 logging.critical(‘critical message‘)
查看输出:
cat /tmp/test.log
Mon, 05 May 2014 16:29:53 test_logging.py[line:9] DEBUG debug message
Mon, 05 May 2014 16:29:53 test_logging.py[line:10] INFO info message
Mon, 05 May 2014 16:29:53 test_logging.py[line:11] WARNING warning message
Mon, 05 May 2014 16:29:53 test_logging.py[line:12] ERROR error message
Mon, 05 May 2014 16:29:53 test_logging.py[line:13] CRITICAL critical message
可见在logging.basicConfig()函数中可通过具体参数来更改logging模块默认行为,可用参数有
filename:用指定的文件名创建FiledHandler(后边会具体讲解handler的概念),这样日志会被存储在指定的文件中。
filemode:文件打开方式,在指定了filename时使用这个参数,默认值为“a”还可指定为“w”。
format:指定handler使用的日志显示格式。
datefmt:指定日期时间格式。
level:设置rootlogger(后边会讲解具体概念)的日志级别
stream:用指定的stream创建StreamHandler。可以指定输出到sys.stderr,sys.stdout或者文件(f=open(‘test.log‘,‘w‘)),默认为sys.stderr。若同时列出了filename和stream两个参数,则stream参数会被忽略。
format参数中可能用到的格式化串:
%(name)s Logger的名字
%(levelno)s 数字形式的日志级别
%(levelname)s 文本形式的日志级别
%(pathname)s 调用日志输出函数的模块的完整路径名,可能没有
%(filename)s 调用日志输出函数的模块的文件名
%(module)s 调用日志输出函数的模块名
%(funcName)s 调用日志输出函数的函数名
%(lineno)d 调用日志输出函数的语句所在的代码行
%(created)f 当前时间,用UNIX标准的表示时间的浮 点数表示
%(relativeCreated)d 输出日志信息时的,自Logger创建以 来的毫秒数
%(asctime)s 字符串形式的当前时间。默认格式是 “2003-07-08 16:49:45,896”。逗号后面的是毫秒
%(thread)d 线程ID。可能没有
%(threadName)s 线程名。可能没有
%(process)d 进程ID。可能没有
%(message)s用户输出的消息
三 logger对象
上述几个例子中我们了解到了logging.debug()、logging.info()、logging.warning()、logging.error()、logging.critical()(分别用以记录不同级别的日志信息),logging.basicConfig()(用默认日志格式(Formatter)为日志系统建立一个默认的流处理器(StreamHandler),设置基础配置(如日志级别等)并加到root logger(根Logger)中)这几个logging模块级别的函数,另外还有一个模块级别的函数是logging.getLogger([name])(返回一个logger对象,如果没有指定名字将返回root logger)
先看一个最简单的过程:
1 import logging 2 3 logger = logging.getLogger() 4 # 创建一个handler,用于写入日志文件 5 fh = logging.FileHandler(‘test.log‘) 6 7 # 再创建一个handler,用于输出到控制台 8 ch = logging.StreamHandler() 9 10 formatter = logging.Formatter(‘%(asctime)s - %(name)s - %(levelname)s - %(message)s‘) 11 12 fh.setFormatter(formatter) 13 ch.setFormatter(formatter) 14 15 logger.addHandler(fh) #logger对象可以添加多个fh和ch对象 16 logger.addHandler(ch) 17 18 logger.debug(‘logger debug message‘) 19 logger.info(‘logger info message‘) 20 logger.warning(‘logger warning message‘) 21 logger.error(‘logger error message‘) 22 logger.critical(‘logger critical message‘)
先简单介绍一下,logging库提供了多个组件:Logger、Handler、Filter、Formatter。Logger对象提供应用程序可直接使用的接口,Handler发送日志到适当的目的地,Filter提供了过滤日志信息的方法,Formatter指定日志显示格式。
(1) Logger是一个树形层级结构,输出信息之前都要获得一个Logger(如果没有显示的获取则自动创建并使用root Logger,如第一个例子所示)。logger = logging.getLogger()返回一个默认的Logger也即root Logger,并应用默认的日志级别、Handler和Formatter设置。当然也可以通过Logger.setLevel(lel)指定最低的日志级别,可用的日志级别有logging.DEBUG、logging.INFO、logging.WARNING、logging.ERROR、logging.CRITICAL。Logger.debug()、Logger.info()、Logger.warning()、Logger.error()、Logger.critical()输出不同级别的日志,只有日志等级大于或等于设置的日志级别的日志才会被输出。
1 logger.debug(‘logger debug message‘) 2 logger.info(‘logger info message‘) 3 logger.warning(‘logger warning message‘) 4 logger.error(‘logger error message‘) 5 logger.critical(‘logger critical message‘)
只输出了
2014-05-06 12:54:43,222 - root - WARNING - logger warning message
2014-05-06 12:54:43,223 - root - ERROR - logger error message
2014-05-06 12:54:43,224 - root - CRITICAL - logger critical message
从这个输出可以看出logger = logging.getLogger()返回的Logger名为root。这里没有用logger.setLevel(logging.Debug)显示的为logger设置日志级别,所以使用默认的日志级别WARNIING,故结果只输出了大于等于WARNIING级别的信息。
(2) 如果我们再创建两个logger对象:
1 ################################################## 2 logger1 = logging.getLogger(‘mylogger‘) 3 logger1.setLevel(logging.DEBUG) 4 5 logger2 = logging.getLogger(‘mylogger‘) 6 logger2.setLevel(logging.INFO) 7 8 logger1.addHandler(fh) 9 logger1.addHandler(ch) 10 11 logger2.addHandler(fh) 12 logger2.addHandler(ch) 13 14 logger1.debug(‘logger1 debug message‘) 15 logger1.info(‘logger1 info message‘) 16 logger1.warning(‘logger1 warning message‘) 17 logger1.error(‘logger1 error message‘) 18 logger1.critical(‘logger1 critical message‘) 19 20 logger2.debug(‘logger2 debug message‘) 21 logger2.info(‘logger2 info message‘) 22 logger2.warning(‘logger2 warning message‘) 23 logger2.error(‘logger2 error message‘) 24 logger2.critical(‘logger2 critical message‘)