PYTHON开发必备技能(2)
第一名:logging模块
知识点示例:
Python中logging模块的基本用法:
默认情况下python的logging模块将日志打印到标准输出流当中,且只显示大于等于warning级别的日志,默认的日志输出格式为:
文本形式的日志级别:logger名称:用户的输出信息。用户可以在logging.basicConfig()函数中通过具体的参数来更改logging模块的默认行为。
日志格式:
%(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 |
用户输出的消息 |
示例1:基本用法
import logging logging.debug('debug message') logging.info('info message') logging.warning('warning message') logging.error('error message') logging.critical('critical message')
示例2:自定义logging.basicConfig
import logging logging.basicConfig(format='%(asctime)s-%(name)s-%(filename)s-[line:%(lineno)d]-%(levelname)s:%(message)s', level=logging.DEBUG) logger = logging.getLogger(__name__) logger.debug('debug message') logger.info('info message') logger.warning('warning message') logger.error('error message') logger.critical('critical message')
自定义组件:Python使用logging模块记录日志涉及到四个主要的类、简述类的名字以及相应的用法:
Logger提供了应用程序可以直接使用的接口
Handler将(logger创建的)日志记录发送到合适的目的输出
Filter提供了细度设备来决定输出哪条日志记录
Formatter决定日志记录的最终输出格式
logging有一个日志处理的主对象,其他处理方式都是通过addHandler添加进去,logging中包含的handler主要有如下几种:
handler名称:位置;作用 StreamHandler:logging.StreamHandler;日志输出到流,可以是sys.stderr,sys.stdout或者文件 FileHandler:logging.FileHandler;日志输出到文件 BaseRotatingHandler:logging.handlers.BaseRotatingHandler;基本的日志回滚方式 RotatingHandler:logging.handlers.RotatingHandler;日志回滚方式,支持日志文件最大数量和日志文件回滚 TimeRotatingHandler:logging.handlers.TimeRotatingHandler;日志回滚方式,在一定时间区域内回滚日志文件 SocketHandler:logging.handlers.SocketHandler;远程输出日志到TCP/IP sockets DatagramHandler:logging.handlers.DatagramHandler;远程输出日志到UDP sockets SMTPHandler:logging.handlers.SMTPHandler;远程输出日志到邮件地址 SysLogHandler:logging.handlers.SysLogHandler;日志输出到syslog NTEventLogHandler:logging.handlers.NTEventLogHandler;远程输出日志到Windows NT/2000/XP的事件日志 MemoryHandler:logging.handlers.MemoryHandler;日志输出到内存中的指定buffer HTTPHandler:logging.handlers.HTTPHandler;通过"GET"或者"POST"远程输出到HTTP服务器
接下来我们通过一些常用的案例来说明logging模块的具体用法:
示例3:配置logging基本的设置,要求:
日志格式:(2017-12-24 12:55:36,083-__main__-日志模块1.py-[line:11]-DEBUG:debug message),并在文件输出相应的日志。
import logging """ 第一:创建一个logger对象 """ logger = logging.getLogger('冷数据归档') logger.setLevel(logging.DEBUG) """ 第二:创建一个Handler对象 """ file_handler = logging.FileHandler(filename='access.log',mode='a') file_handler.setLevel(logging.DEBUG) """ 第三:创建一个formatter对象,并设置相应的格式 """ formatter = logging.Formatter('%(asctime)s-%(name)s-%(filename)s-[line:%(lineno)d]-%(levelname)s:%(message)s', datefmt='%Y-%m-%d %H:%M:%S %p') """ 最后:拼接logger、handler、formatter之间的关系 """ file_handler.setFormatter(formatter) logger.addHandler(file_handler) logger.debug('debug message') logger.info('info message') logger.warning('warning message') logger.error('error message') logger.critical('critical message')
示例4:配置logging基本的设置,要求:
日志格式:(2017-12-24 12:55:36,083-__main__-日志模块1.py-[line:11]-DEBUG:debug message),并要求在文件和控制台当中输出相应的日志。
import logging """ 第一步:创建一个logger """ logger = logging.getLogger(__name__) logger.setLevel(logging.DEBUG) """ 第二步:创建两个Handler==>fileHandler和screenHandler """ screen_handler = logging.StreamHandler() screen_handler.setLevel(logging.DEBUG) file_handler = logging.FileHandler(filename='access.log',mode='a') file_handler.setLevel(logging.DEBUG) """ 第三步:创建一个formatter,指定日志的输出格式 """ formatter = logging.Formatter('%(asctime)s-%(name)s-%(filename)s-[line:%(lineno)d]-%(levelname)s:%(message)s', datefmt='%Y-%m-%d %H:%M:%S %p') """ 第四步骤:将logger、handler与formatter进行拼接 """ file_handler.setFormatter(formatter) screen_handler.setFormatter(formatter) logger.addHandler(file_handler) logger.addHandler(screen_handler) logger.debug('debug message') logger.info('info message') logger.warning('warning message') logger.error('error message') logger.critical('critical message')
文件中的输出日志:
2017-12-24 13:32:03 PM-__main__-日志模块1.py-[line:37]-DEBUG:debug message 2017-12-24 13:32:03 PM-__main__-日志模块1.py-[line:38]-INFO:info message 2017-12-24 13:32:03 PM-__main__-日志模块1.py-[line:39]-WARNING:warning message 2017-12-24 13:32:03 PM-__main__-日志模块1.py-[line:40]-ERROR:error message 2017-12-24 13:32:03 PM-__main__-日志模块1.py-[line:41]-CRITICAL:critical message 2017-12-24 13:32:15 PM-__main__-日志模块1.py-[line:37]-DEBUG:debug message 2017-12-24 13:32:15 PM-__main__-日志模块1.py-[line:38]-INFO:info message 2017-12-24 13:32:15 PM-__main__-日志模块1.py-[line:39]-WARNING:warning message 2017-12-24 13:32:15 PM-__main__-日志模块1.py-[line:40]-ERROR:error message 2017-12-24 13:32:15 PM-__main__-日志模块1.py-[line:41]-CRITICAL:critical message
当然,我们可以将上面的代码用一个函数实现,做成一个现成的组件。
import logging def get_logger(): """ 第一步:创建一个logger """ logger = logging.getLogger(__name__) logger.setLevel(logging.DEBUG) """ 第二步:创建两个Handler==>fileHandler和screenHandler """ screen_handler = logging.StreamHandler() screen_handler.setLevel(logging.DEBUG) file_handler = logging.FileHandler(filename='access.log',mode='a') file_handler.setLevel(logging.DEBUG) """ 第三步:创建一个formatter,指定日志的输出格式 """ formatter = logging.Formatter('%(asctime)s-%(name)s-%(filename)s-[line:%(lineno)d]-%(levelname)s:%(message)s', datefmt='%Y-%m-%d %H:%M:%S %p') """ 第四步骤:将logger、handler与formatter进行拼接 """ file_handler.setFormatter(formatter) screen_handler.setFormatter(formatter) logger.addHandler(file_handler) logger.addHandler(screen_handler) return logger if __name__ == '__main__': logger = get_logger() logger.debug('debug message') logger.info('info message') logger.warning('warning message') logger.error('error message') logger.critical('critical message')
第二名:subprocess模块(Popen)
从Python2.4开始,Python引入subprocess模块来管理子进程,已取代一些旧模块的使用方法,如:
os.system、os.spawn*、os.popen*、popen2.*、commands.*等。
Python中子进程模块subprocess的作用:
This module allows you to spawn processes, connect to their input/output/error pipes, and obtain their return codes. This module intends to replace several older modules and functions: os.system os.spawn*
subprocess的目的就是启动一个新的进程并且与之通信;
通过subprocess模块不但可以调用外部的命令创建一个新的子进程,而且可以连接到子进程的input、output、error管道,获取相
关的返回信息。
用法大汇总如下表所示:
Python中subprocess模块中call()的使用方式:
父进程等待子进程执行命令(完成),并返回子进程执行命令的状态码。
示例代码:
#!/usr/bin/python # -*- coding:utf-8 -*- import subprocess returncode = subprocess.call('ping -c 3 -i 3 www.baidu.com',shell=True) if returncode == 0: print('当前命令执行成功') else: print('当前命令执行失败')
print("over......")
运行结果:
接下来我们通过Popen方法来实现相同的功能:
#!/usr/bin/python # -*- coding:utf-8 -*- import subprocess child = subprocess.Popen('ping -c 3 -i 3 www.baidu.com',shell=True) child.wait() if child.returncode == 0: print('子进程执行成功.') else: print('子进程执行失败') print("over.....")
Python中subprocess模块中check_call()的使用方式:
父进程等待子进程执行命令(完成),并返回子进程执行命令的状态码,如果出现错误,Python解释器会进行报错。
代码示例:
#!/usr/bin/python # -*- coding:utf-8 -*- import subprocess returncode = 0 """ 注意:对于下面的代码而言,如果子进程抛出异常的话,returncode不会被赋值,此时下面 的代码不会访问到returncode变量;但是如果不抛出异常,则可以访问到该变量 """ try: returncode = subprocess.check_call('ping -c 3 -zhangi zhang3 www.baidu.com',shell=True) except Exception as e: print('子进程运行失败,抛出的异常信息是:%s'%str(e)) print('抛出的异常状态的码值是:%s'%e.returncode) returncode = e.returncode if returncode == 0: print('子进程命令执行成功') else: print('子进程执行失败') for i in range(0,10): print(i)
改进:
#!/usr/bin/python # -*- coding:utf-8 -*- import subprocess try: returncode = subprocess.check_call('ping -c 3 -i 3 www.baidu.com',shell=True) except Exception as e: print(str(e)) else: if returncode == 0: print('子进程执行成功..') for i in range(0,10): print(i)
接下来我们通过Popen方法来实现相同的功能:
代码:
#!/usr/bin/python # -*- coding:utf-8 -*- import subprocess child = subprocess.Popen('ping -czhang 3ming -i 3 www.baidu.com',shell=True,stderr=subprocess.PIPE) child.wait() if child.returncode == 0: print('子进程执行成功') else: print('子进程执行失败') print('子进程抛出的异常信息是:%s'%child.stderr.read().decode('utf-8'))
Python中subprocess模块中check_output()的使用方式:
父进程等待子进程执行命令(完成),并返回子进程执行命令的运行结果,如果出现错误,Python解释器会进行报错
示例程序:
#!/usr/bin/python # -*- coding:utf-8 -*- import subprocess returncode = 0 try: result = subprocess.check_output('ping -c 3 -i 3 www.baidu.com',shell=True) except Exception as e: print('子进程执行失败,抛出的异常信息是:%s'%str(e)) print('子进程返回的状态码值是:%s'%(e.returncode)) returncode = e.returncode if returncode == 0: print('子进程执行成功') print('子进程输出的运行结果是:%s'%result.decode('utf-8')) else: print('子进程执行失败')
运行结果:
子进程执行成功 子进程输出的运行结果是:PING www.a.shifen.com (61.135.169.121) 56(84) bytes of data. 64 bytes from 61.135.169.121 (61.135.169.121): icmp_seq=1 ttl=55 time=1.27 ms 64 bytes from 61.135.169.121 (61.135.169.121): icmp_seq=2 ttl=55 time=1.05 ms 64 bytes from 61.135.169.121 (61.135.169.121): icmp_seq=3 ttl=55 time=1.29 ms --- www.a.shifen.com ping statistics --- 3 packets transmitted, 3 received, 0% packet loss, time 6006ms rtt min/avg/max/mdev = 1.056/1.207/1.290/0.106 ms
通过Popen我们来实现同样的功能:
#!/usr/bin/python # -*- coding:utf-8 -*- import subprocess child = subprocess.Popen('ping -c 3 -i 3 www.baidu.com',shell=True,stdout=subprocess.PIPE,stderr=subprocess.PIPE) child.wait() if child.returncode == 0: print('子进程执行成功') print('子进程返回的运行结果是:%s'%child.stdout.read().decode('utf-8')) else: print('子进程执行失败') print('子进程抛出的异常信息是:%s'%child.stderr.read().decode('utf-8'))
Python中subprocess模块中getstatusoutput()的使用方式:
父进程等待子进程执行命令,并返回子进程执行命令的状态码和运行结果,如果出现错误,Python解释器不会进行报错,而是将其报错
信息保存在运行结果当中
注意:这个命令不用写shell=True,并且只能用python3运行
示例程序:
#!/usr/bin/python # -*- coding:utf-8 -*- import subprocess returncode,result = subprocess.getstatusoutput('ping -c 3 -i 3 www.baidu.com') if returncode == 0: print('子进程执行成功') print('子进程输出的运行结果是:%s'%result) else: print('子进程执行失败') print('子进程抛出的异常信息是:%s'%result)
运行结果:
子进程执行成功 子进程输出的运行结果是:PING www.a.shifen.com (61.135.169.125) 56(84) bytes of data. 64 bytes from 61.135.169.125 (61.135.169.125): icmp_seq=1 ttl=55 time=1.06 ms 64 bytes from 61.135.169.125 (61.135.169.125): icmp_seq=2 ttl=55 time=1.15 ms 64 bytes from 61.135.169.125 (61.135.169.125): icmp_seq=3 ttl=55 time=1.03 ms --- www.a.shifen.com ping statistics --- 3 packets transmitted, 3 received, 0% packet loss, time 6003ms rtt min/avg/max/mdev = 1.030/1.083/1.155/0.064 ms
接下来我们通过Popen实现相同的功能:
#!/usr/bin/python # -*- coding:utf-8 -*- import subprocess child = subprocess.Popen('ping -c 3 -i 3 www.baidu.com',shell=True,stdout=subprocess.PIPE,stderr=subprocess.PIPE) child.wait() if child.returncode == 0: print('子进程运行成功') print('子进程的输出结果是:%s'%child.stdout.read().decode('utf-8')) else: print('子进程运行失败,抛出的异常信息是:%s') print(child.stderr.read())
运行结果:
子进程运行成功 子进程的输出结果是:PING www.a.shifen.com (61.135.169.125) 56(84) bytes of data. 64 bytes from 61.135.169.125 (61.135.169.125): icmp_seq=1 ttl=55 time=1.14 ms 64 bytes from 61.135.169.125 (61.135.169.125): icmp_seq=2 ttl=55 time=1.18 ms 64 bytes from 61.135.169.125 (61.135.169.125): icmp_seq=3 ttl=55 time=1.21 ms --- www.a.shifen.com ping statistics --- 3 packets transmitted, 3 received, 0% packet loss, time 6005ms rtt min/avg/max/mdev = 1.142/1.178/1.211/0.048 ms
如何更好的理解:subprocess.STDOUT?
#!/usr/bin/python # -*- coding:utf-8 -*- import subprocess fr = open('log.txt',encoding='utf-8',mode='w') #-------------------------------- # subprocess.STDOUT:将标准错误重定向到标准输出的同一个句柄(在这里代表写到同样一个文件) #-------------------------------- child = subprocess.Popen('ping -c 3 -i 3 www.baidu.com',shell=True,stdout=fr,stderr=subprocess.STDOUT) child.wait() for i in range(0,10): print(i)
运行结果:
[root@hadoop11 zmy]# more log.txt PING www.a.shifen.com (220.181.111.188) 56(84) bytes of data. 64 bytes from 220.181.111.188 (220.181.111.188): icmp_seq=1 ttl=54 time=3.70 ms 64 bytes from 220.181.111.188 (220.181.111.188): icmp_seq=2 ttl=54 time=3.71 ms 64 bytes from 220.181.111.188 (220.181.111.188): icmp_seq=3 ttl=54 time=3.76 ms --- www.a.shifen.com ping statistics --- 3 packets transmitted, 3 received, 0% packet loss, time 6004ms rtt min/avg/max/mdev = 3.707/3.729/3.765/0.025 ms
Python中subprocess模块中Popen()的使用方式:
通过上面的这些程序,我们发现,Popen是万能的。
第一:subprocess模块中的很多方法本质上都是基于Popen方法的封装,封装的目的在于让我们更容易使用子进程,Popen类生成的对象代表子进程
第二:Popen对象创建后,主进程不会自动等待子进程执行完成,我们必须调用子进程对象的wait()方法,父进程才会等待子进程执行完成
第三:子进程的标准输入、标准输出和标准错误分别用如下属性表示:
child.stdin 、child.stdout 、child.stderr
第四:我们可以在subprocess.Popen()建立子进程的时候改变标准输入、标准输出和标准错误的方向,并可以利用subprocess.PIPE将多个子进程的输入和输出连接在一起,构成管道(pipe)
第五:subprocess.PIPE实际上为文本流提供一个缓存区。
标准输入和标准输出示例1:
#!/usr/bin/python # -*- coding:utf-8 -*- import subprocess child = subprocess.Popen('ping -c 3 -i 3 www.baidu.com', shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE) child.wait() if child.returncode == 0: print('子进程执行成功') print('子进程返回的运行结果是:%s' % child.stdout.read().decode('utf-8')) else: print('子进程执行失败') print('子进程抛出的异常信息是:%s' % child.stderr.read().decode('utf-8'))
代码示例2:
#!/usr/bin/python # -*- coding:utf-8 -*- import subprocess child1 = subprocess.Popen('cat ./word.txt',shell=True,stdout=subprocess.PIPE) child1.wait() child2 = subprocess.Popen('grep wangtingting',shell=True,stdin=child1.stdout,stdout=subprocess.PIPE) child2.wait() if child2.returncode == 0: print('子进程执行成功,其运行结果为:%s'%child2.stdout.read().decode('utf-8')) else: print('子进程执行失败')
分析:
child1的stdout将其运行结果输出到缓存区,随后child2的stdin从该PIPE中将文本读取走,child2的输出文本也被存放在PIPE
中,直到从PIPE中读取出文本。
示例程序3:
#!/usr/bin/python # -*- coding:utf-8 -*- """ 如何更好的理解:subprocess.STDOUT? #-------------------------------- # stderr=subprocess.STDOUT:将标准错误和标准输出写到同一个管道里面. #-------------------------------- """ import subprocess child = subprocess.Popen('ping -c 3 -i 3 www.baidu.com', shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) child.wait() if child.returncode == 0: print('子进程执行成功') print('子进程返回的运行结果是:%s' % child.stdout.read().decode('utf-8')) else: print('子进程执行失败') print('子进程抛出的异常信息是:%s' % child.stdout.read().decode('utf-8'))
第三名:时间模块(time和datetime)
1、time.time()时间戳的概念
指格林威治时间1970年01月01日00时00分00秒(北京时间1970年01月01日08时00分00秒)起至现在的总秒数
2、time.gmtime()和time.localtime()的作用
time.gmtime():返回格林威治时间的时间对象
time.localtime():返回本地时间的时间对象
3、time.mktime()的作用
通过该函数可以将时间对象转化成时间戳
4、time.strftime()和time.strptime()的作用
time.strftime():可以将时间对象按照指定的格式进行输出
time.strptime():将字符串按照指定的格式转化成时间对象(必须配对)
5、时间模块中时间的分类
时间戳、时间对象、可视化时间
示例程序1:
import time print(time.asctime()) print(time.ctime())
运行结果:
Fri Jan 19 18:02:53 2018 Fri Jan 19 18:02:53 2018
示例程序2:将本地时间戳按照年月日时分秒的格式进行输出
import time time_stamp = time.time() print(time_stamp) time_struct = time.localtime(time_stamp) print(time_struct) time_view = time.strftime('%Y-%m-%d %H:%M:%S',time_struct) print(time_view) #当然我们可以通过下面一句话执行上面所有的功能 now_time = time.strftime('%Y-%m-%d %H:%M:%S',time.localtime(time.time())) print('\033[42m%s\033[0m'%now_time)
运行结果:
1516356884.213294 time.struct_time(tm_year=2018, tm_mon=1, tm_mday=19, tm_hour=18, tm_min=14, tm_sec=44, tm_wday=4, tm_yday=19, tm_isdst=0) 2018-01-19 18:14:44 2018-01-19 18:14:44
示例程序3:将2018-01-19 18:14:44转化成对应的时间戳
import time time_struct = time.strptime('2018-01-19 18:14:44','%Y-%m-%d %H:%M:%S') print(time_struct) time_stamp = time.mktime(time_struct) print(time_stamp) #当然我们可以用一句话来进行替代 time_stamp = time.mktime(time.strptime('2018-01-19 18:14:44','%Y-%m-%d %H:%M:%S')) print(time_stamp)
运行结果:
time.struct_time(tm_year=2018, tm_mon=1, tm_mday=19, tm_hour=18, tm_min=14, tm_sec=44, tm_wday=4, tm_yday=19, tm_isdst=-1) 1516356884.0 1516356884.0
示例程序4:获取昨天的日期,并按照年月日的形式进行输出
import time #获取昨天的日期,并按照年月日的形式进行输出 time_stamp = time.time() print(time_stamp) time_struct = time.localtime(time_stamp - 24*60*60) print(time_struct) time_view = time.strftime('%Y-%m-%d %H:%M:%S',time_struct) print(time_view) #简单的操作 time_view = time.strftime('%Y-%m-%d %H:%M:%S',time.localtime(time.time() - 24*60*60)) print(time_view)
运行结果:
1516357631.853695 time.struct_time(tm_year=2018, tm_mon=1, tm_mday=18, tm_hour=18, tm_min=27, tm_sec=11, tm_wday=3, tm_yday=18, tm_isdst=0) 2018-01-18 18:27:11 2018-01-18 18:27:11 Process finished with exit code 0
datetime模块的相关用法:(我很少用)
datetime模块:(打印时间、时间的运算、以及时间的替换)
datetime.datetime.now() :将当前日期打印出来
datetime.date.fromtimestamp(time.time()) :将时间戳直接转化成日期格式
注意:但是这个方法虽然简单,但是却不能够按照指定的格式进行输出,所以我们一般很少用。
import datetime import time print(datetime.datetime.now()) print(datetime.date.fromtimestamp(time.time())) print(datetime.datetime.fromtimestamp(time.time())) print(datetime.datetime.now() + datetime.timedelta(3)) print(datetime.datetime.now() + datetime.timedelta(3)) print(datetime.datetime.now() + datetime.timedelta(-3)) print(datetime.datetime.now() + datetime.timedelta(hours=3)) print(datetime.datetime.now() + datetime.timedelta(minutes=30)) c_time = datetime.datetime.now() print(c_time.replace(minute=3,hour=2))
运行结果:
2018-01-19 18:34:05.053005 2018-01-19 2018-01-19 18:34:05.053005 2018-01-22 18:34:05.053005 2018-01-22 18:34:05.053005 2018-01-16 18:34:05.054005 2018-01-19 21:34:05.054005 2018-01-19 19:04:05.054005 2018-01-19 02:03:05.054005 Process finished with exit code 0
自定制函数功能:
#!/usr/bin/python # -*- coding:utf-8 -*- import datetime import time def get_time(num): """ function:本函数的功能是获取指定格式的时间(可以自定制任意一天),num=0的话代表当天时间 """ time_stamp = time.time() time_struct = time.localtime(time_stamp + 24*60*60*num) time_view = time.strftime('%Y-%m-%d %H:%M:%S',time_struct) return time_view if __name__ == '__main__': user_time = get_time(-3) print(user_time)
项目中常见的一些场景:
import time import datetime today = datetime.date.today() print(today) today = datetime.date.fromtimestamp(time.time()) print(today) yesterday = datetime.date.fromtimestamp(time.time()-24*60*60) print(yesterday) time_lable = datetime.datetime.now() print(time_lable) yesterday_lable = datetime.datetime.now() - datetime.timedelta(1) print(yesterday_lable)
运行结果:
2018-04-05 2018-04-05 2018-04-04 2018-04-05 13:52:08.364681 2018-04-04 13:52:08.364695