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')
可见,默认情况下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='test.log', 6 ) # filemode='a' 7 8 9 logging.debug('debug message11') 10 logging.info('info message22') 11 logging.warning('hello error33') 12 logging.error('error message44') 13 logging.critical('critical message55')
保存的内容为
Wed,14 Sep 2016 16:09:48 modue_test.py[line:46] DEBUG debug message11 Wed,14 Sep 2016 16:09:48 modue_test.py[line:47] INFO info message22 Wed,14 Sep 2016 16:09:48 modue_test.py[line:48] WARNING hello error33 Wed,14 Sep 2016 16:09:48 modue_test.py[line:49] ERROR error message44 Wed,14 Sep 2016 16:09:48 modue_test.py[line:50] CRITICAL critical message55
可见在logging.basicConfig()函数中可通过具体参数来更改logging模块默认行为,可用参数有
filename:用指定的文件名创建FiledHandler(后边会具体讲解handler的概念),这样日志会被存储在指定的文件中。
filemode:文件打开方式,在指定了filename时使用这个参数,默认值为“a”还可指定为“w”。
format:指定handler使用的日志显示格式。
datefmt:指定日期时间格式。
level:设置rootlogger(后边会讲解具体概念)的日志级别
stream:用指定的stream创建StreamHandler。可以指定输出到sys.stderr,sys.stdout或者文件,默认为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.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 14 ch.setFormatter(formatter) 15 16 logger.addHandler(fh) 17 logger.addHandler(ch) 18 19 logger.setLevel(logging.DEBUG) 20 21 logger.debug('logger debug message') 22 logger.info('logger info message') 23 logger.warning('logger warning message') 24 logger.error('logger error message') 25 logger.critical('logger critical message')
运行后在文件与屏幕上同时输出
2016-09-14 16:13:43,774 - root - DEBUG - logger debug message 2016-09-14 16:13:43,775 - root - INFO - logger info message 2016-09-14 16:13:43,775 - root - WARNING - logger warning message 2016-09-14 16:13:43,775 - root - ERROR - logger error message 2016-09-14 16:13:43,775 - root - CRITICAL - logger critical message
configparser 模块
来看一个好软件的常见文档格式如下:
1 [DEFAULT] 2 ServerAliveInterval = 45 3 Compression = yes 4 CompressionLevel = 9 5 ForwardX11 = yes 6 7 [bitbucket.org] 8 User = hg 9 10 [topsecret.server.com] 11 Port = 50022 12 ForwardX11 = no
如果想用python生成一个这样的文档怎么做呢?
1 import configparser 2 3 config = configparser.ConfigParser() 4 config["DEFAULT"] = {'ServerAliveInterval': '45', 5 'Compression': 'yes', 6 'CompressionLevel': '9'} 7 8 config['bitbucket.org'] = {} 9 config['bitbucket.org']['User'] = 'hg' 10 config['topsecret.server.com'] = {} 11 topsecret = config['topsecret.server.com'] 12 topsecret['Host Port'] = '50022' # mutates the parser 13 topsecret['ForwardX11'] = 'no' # same here 14 config['DEFAULT']['ForwardX11'] = 'yes'
15 with open('example.ini', 'w') as configfile: 16 config.write(configfile)
增删改查
1 import configparser 2 3 config = configparser.ConfigParser() 4 5 #---------------------------------------------查 6 print(config.sections()) #[] 7 8 config.read('example.ini') 9 10 print(config.sections()) #['bitbucket.org', 'topsecret.server.com'] 11 12 print('bytebong.com' in config)# False 13 14 print(config['bitbucket.org']['User']) # hg 15 16 print(config['DEFAULT']['Compression']) #yes 17 18 print(config['topsecret.server.com']['ForwardX11']) #no 19 20 21 for key in config['bitbucket.org']: 22 print(key) 23 24 25 # user 26 # serveraliveinterval 27 # compression 28 # compressionlevel 29 # forwardx11 30 31 32 print(config.options('bitbucket.org'))#['user', 'serveraliveinterval', 'compression', 'compressionlevel', 'forwardx11'] 33 print(config.items('bitbucket.org')) #[('serveraliveinterval', '45'), ('compression', 'yes'), ('compressionlevel', '9'), ('forwardx11', 'yes'), ('user', 'hg')] 34 35 print(config.get('bitbucket.org','compression'))#yes 36 37 38 #---------------------------------------------删,改,增(config.write(open('i.cfg', "w"))) 39 40 41 config.add_section('yuan') 42 43 config.remove_section('topsecret.server.com') 44 config.remove_option('bitbucket.org','user') 45 46 config.set('bitbucket.org','k1','11111') 47 48 config.write(open('i.cfg', "w")) 49 50 增删改查
json & pickle
序列化
我们把对象(变量)从内存中变成可存储或传输的过程称为序列化
序列化之后,就可以把序列化后的内容写入磁盘,或者通过网络传输到别的机器上
反过来,把变量内容从序列化的对象重新读到内存里称之为反序列化
json
如果我们要在不同的编程语言之间传递对象,就必须把对象序列化为标准格式,比如XML,但更好的方法是序列化为json,因为json表示出来就是一个字符串,可以被所有语言读取,也可以方便地存储到磁盘或者通过网络传输。json不仅是标准格式,而且比XML更快,而且可以直接在Wab页面中读取,非常方便。
1 import json 2 3 dic={'name':'alvin','age':23,'sex':'male'} 4 print(type(dic)) #5 6 j=json.dumps(dic) 7 print(type(j)) # 8 9 10 f=open('序列化对象','w') 11 f.write(j) #-------------------等价于json.dump(dic,f) 12 f.close() 13 #-----------------------------反序列化
14 import json 15 f=open('序列化对象') 16 data=json.loads(f.read()) # 等价于data=json.load(f)
1 import json 2 #dct="{'1':111}"#json 不认单引号 3 #dct=str({"1":111})#报错,因为生成的数据还是单引号:{'one': 1} 4 5 dct='{"1":"111"}' 6 print(json.loads(dct)) 7 8 #conclusion: 9 # 无论数据是怎样创建的,只要满足json格式,就可以json.loads出来,不一定非要dumps的数据才能loads 10 11 注意点
保存的时候有两个方法dump和dumps
读取的时候有两个方法load和loads
1 import json 2 # import pickle 3 f = open("666.txt", "w") 4 5 dic = {"j": "d", "6": "dd"} 6 # dic = json.dumps(dic) 7 # f.write(dic) 8 json.dump(dic, f) 9 # dic = pickle.dumps(dic) 10 print(type(dic)) 11 12 13 f.close() 14 15 ######### 注意两种方法的不同 ########## 16 import json 17 18 f = open("666.txt", "r") 19 20 # data = json.loads(f.read()) 21 data = json.load(f) 22 print(data) 23 # print(type(f.read())) 24 f.close()
pickle
pickle的使用方法与json类似,但是pickle只能用于python,并且能保存json不能保存的类型
subprocess
subprocess模块的主要功能是执行外部的命令和程序
subprocess模块允许一个进程创建一个新的子进程,通过管道连接到子进程的stdin/stdout/stderr,获取子进程的返回值等操作
模块有一个重要类: Popen
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)
1 # 参数args可以是字符串或者序列类型(如:list,元组),用于指定进程的可执行文件及其参数。 2 # 如果是序列类型,第一个元素通常是可执行文件的路径。我们也可以显式的使用executeable参 3 # 数来指定可执行文件的路径。在windows操作系统上,Popen通过调用CreateProcess()来创 4 # 建子进程,CreateProcess接收一个字符串参数,如果args是序列类型,系统将会通过 5 # list2cmdline()函数将序列类型转换为字符串。 6 # 7 # 8 # 参数bufsize:指定缓冲。我到现在还不清楚这个参数的具体含义,望各个大牛指点。 9 # 10 # 参数executable用于指定可执行程序。一般情况下我们通过args参数来设置所要运行的程序。如 11 # 果将参数shell设为True,executable将指定程序使用的shell。在windows平台下,默认的 12 # shell由COMSPEC环境变量来指定。 13 # 14 # 参数stdin, stdout, stderr分别表示程序的标准输入、输出、错误句柄。他们可以是PIPE, 15 # 文件描述符或文件对象,也可以设置为None,表示从父进程继承。 16 # 17 # 参数preexec_fn只在Unix平台下有效,用于指定一个可执行对象(callable object),它将 18 # 在子进程运行之前被调用。 19 # 20 # 参数Close_sfs:在windows平台下,如果close_fds被设置为True,则新创建的子进程将不会 21 # 继承父进程的输入、输出、错误管道。我们不能将close_fds设置为True同时重定向子进程的标准 22 # 输入、输出与错误(stdin, stdout, stderr)。 23 # 24 # 如果参数shell设为true,程序将通过shell来执行。 25 # 26 # 参数cwd用于设置子进程的当前目录。 27 # 28 # 参数env是字典类型,用于指定子进程的环境变量。如果env = None,子进程的环境变量将从父 29 # 进程中继承。 30 # 31 # 参数Universal_newlines:不同操作系统下,文本的换行符是不一样的。如:windows下 32 # 用’/r/n’表示换,而Linux下用’/n’。如果将此参数设置为True,Python统一把这些换行符当 33 # 作’/n’来处理。 34 # 35 # 参数startupinfo与createionflags只在windows下用效,它们将被传递给底层的 36 # CreateProcess()函数,用于设置子进程的一些属性,如:主窗口的外观,进程的优先级等等。 37 38 parameter
简单命令
1 # 此为linux下运行 2 import subprocess 3 4 a=subprocess.Popen('ls')# 创建一个新的进程,与主进程不同步 5 6 print('>>>>>>>',a)#a是Popen的一个实例对象 7 8 ''' 9 >>>>>>>10 __init__.py 11 __pycache__ 12 log.py 13 main.py 14 15 ''' 16 17 # subprocess.Popen('ls -l',shell=True) 18 19 # subprocess.Popen(['ls','-l'])
subprocess.PIPE
在创建Popen对象时,subprocess.PIPE可以初始化stdin,std,out,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
Popen的方法
Popen.poll() 用于检查子进程是否已经结束。设置并返回returncode属性。 Popen.wait() 等待子进程结束。设置并返回returncode属性。 Popen.communicate(input=None) 与子进程进行交互。向stdin发送数据,或从stdout和stderr中读取数据。可选参数input指定发送到子进程的参数。 Communicate()返回一个元组:(stdoutdata, stderrdata)。注意:如果希望通过进程的stdin向其发送数据,在创建Popen对象的时候,参数stdin必须被设置为PIPE。同样,如 果希望从stdout和stderr获取数据,必须将stdout和stderr设置为PIPE。 Popen.send_signal(signal) 向子进程发送信号。 Popen.terminate() 停止(stop)子进程。在windows平台下,该方法将调用Windows API TerminateProcess()来结束子进程。 Popen.kill() 杀死子进程。 Popen.stdin 如果在创建Popen对象是,参数stdin被设置为PIPE,Popen.stdin将返回一个文件对象用于策子进程发送指令。否则返回None。 Popen.stdout 如果在创建Popen对象是,参数stdout被设置为PIPE,Popen.stdout将返回一个文件对象用于策子进程发送指令。否则返回 None。 Popen.stderr 如果在创建Popen对象是,参数stdout被设置为PIPE,Popen.stdout将返回一个文件对象用于策子进程发送指令。否则返回 None。 Popen.pid 获取子进程的进程ID。 Popen.returncode 获取进程的返回值。如果进程还没有结束,返回None。
subprocess模块的工具函数
supprocess模块提供了一些函数,方便我们用于创建进程来实现一些简单的功能。 subprocess.call(*popenargs, **kwargs) 运行命令。该函数将一直等待到子进程运行结束,并返回进程的returncode。如果子进程不需要进行交 互,就可以使用该函数来创建。 subprocess.check_call(*popenargs, **kwargs) 与subprocess.call(*popenargs, **kwargs)功能一样,只是如果子进程返回的returncode不为0的话,将触发CalledProcessError异常。在异常对象中,包 括进程的returncode信息。 check_output(*popenargs, **kwargs) # 重要 与call()方法类似,以byte string的方式返回子进程的输出,如果子进程的返回值不是0,它抛出CalledProcessError异常,这个异常中的returncode包含返回码,output属性包含已有的输出。 getstatusoutput(cmd)/getoutput(cmd) 这两个函数仅仅在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' 42 43 演示