文成小盆友python-num5 -装饰器回顾,模块,字符串格式化
一。装饰器回顾与补充
- 单层装饰器:
如上篇文章所讲单层装饰器指一个函数用一个装饰器来装饰,即在函数执行前或者执行后用于添加相应的操作(如判断某个条件是否满足)。
具体请见如下:
- 双层装饰器
双层解释器在原理上相同,只是在执行时比单层复杂。见如下实例:
需求: 做一个简单的登录展示,有两个菜单即可一个菜单仅需要登录后就能查看,一个菜单不但需要登录,而且还得需要是超级管理员登录才能查看。
分析:1.可以写一个装饰器,在着一个装饰器中判断是否满足两个条件如果满足着执行函数体,但问题是还有一个菜单是不需要两个都判断的,所以这样写在一个装饰器的方案不容易实现,
而且还无法满足后续程序的扩展(如,某一天又需要在判断一个条件则还得在改装饰器函数,这样就违背了当初用装饰器的目的)。
解决:使用多个装饰器来判断条件,每个装饰器判断一个条件,灵活。如下代码实现:
如下代码仅为测试使用,双层解释器,模拟是否登录可以采用修改USER_INFO的is_log_in的值,True表示已经登录,同样的user_type表示是否为admin用户。
1 ####双层装饰器:############## 2 #如下定义一个字典用于存放登录状态和,用户类型。 3 USER_INFO = {"is_log_in":True,"user_type":0} 4 5 6 def check_log(func): 7 ''' 8 装饰器一,用于判断用户是否已经登录 9 :param func: 10 :return: 11 ''' 12 def inner(*args,**kwargs): 13 if USER_INFO.get("is_log_in"): 14 res = func(*args,**kwargs) 15 return res 16 else: 17 print("必须先登录--") 18 return inner 19 20 def check_admin(func): 21 ''' 22 装饰器二,用于判断登录用户是否是admin 23 :param func: 24 :return: 25 ''' 26 def inner(*args,**kwargs): 27 if int(USER_INFO.get("user_type")) == 1: 28 rest = func() 29 return rest 30 else: 31 print("必须为超级用户才能够操作--") 32 return inner 33 34 35 36 @check_log 37 def login (): 38 ''' 39 选择1后展示的内容。 40 :return: 41 ''' 42 print("-------普通用户界面————————") 43 44 @check_log 45 @check_admin 46 def index(): 47 ''' 48 选择2后展示的内容 49 :return: 50 ''' 51 print("超级管理员页面") 52 53 54 def main(): 55 ''' 56 主函数用于展示和获取用户输入。 57 :return: 58 ''' 59 while True: 60 print("1.普通用户界面 2.超级管理员界面") 61 userchoice = int(input(">>> ")) 62 if userchoice == 1: 63 login() 64 65 if userchoice == 2: 66 index() 67 68 main()
双层修饰器的执行过程如下:
1.当两个装饰器同时引用时,执行第一个装饰器的时候,这时候传递给第一个装饰器的参数就是第二个装饰器连同下面的原函数。
2,而再执行到第二个装饰器的时候,这个装饰器的参数就是真正的原函数。
装饰器的主要原则如上,多层可以以此类推。
二。详细字符串的格式化:
ptyhon的字符串有两种方法,一种是使用百分号的方法,一种为使用format() 方法来完成字符串的格式化,对于两者来说目前共存,相比较而言format方法提供的
功能更加丰富,比较先进,下面为两种方法的详细使用方法。
1.百分号方式
使用方法:
#
%[(name)][flags][width].[precision]typecode
name -- 可选参数,用于指定可用的key(引用时必须指定name的值,顺序可以不一致。)
flags --可选参数,如下的值可以选择:
- +: 右对齐,正数前加正号,负数前加负号
- - 左对齐,正数前无符号,负数前加负号
- 空格 右对齐,正数前加空格,负数前加负号
- 0 右对齐,正数前无符号,负数前加负号,用0填充空白区。
width -- 可选参数,用于指定占位符所占有的宽度。
.precision --可选参数,用于指定小数点后保留的位数。
typecode --必选参数,可用值如下:
- s,获取传入对象的__str__方法的返回值,并将其格式化到指定位置
- r,获取传入对象的__repr__方法的返回值,并将其格式化到指定位置
- c,整数:将数字转换成其unicode对应的值,10进制范围为 0 <= i <= 1114111(py27则只支持0-255);字符:将字符添加到指定位置
- o,将整数转换成 八 进制表示,并将其格式化到指定位置
- x,将整数转换成十六进制表示,并将其格式化到指定位置
- d,将整数、浮点数转换成 十 进制表示,并将其格式化到指定位置
- e,将整数、浮点数转换成科学计数法,并将其格式化到指定位置(小写e)
- E,将整数、浮点数转换成科学计数法,并将其格式化到指定位置(大写E)
- f, 将整数、浮点数转换成浮点数表示,并将其格式化到指定位置(默认保留小数点后6位)
- F,同上
- g,自动调整将整数、浮点数转换成 浮点型或科学计数法表示(超过6位数用科学计数法),并将其格式化到指定位置(如果是科学计数则是e;)
- G,自动调整将整数、浮点数转换成 浮点型或科学计数法表示(超过6位数用科学计数法),并将其格式化到指定位置(如果是科学计数则是E;)
- %,当字符串中存在格式化标志时,需要用 %%表示一个百分号
以上参数中并没有将正数转换成二进制的方式,这种效果 可以通过format(),方法来实现。
使用百分号方式格式化,如下实例:
1 # -*- coding:utf-8 -*- 2 # Author:wencheng.zhao 3 4 s1 = "my name is %s " % ("赵文成") #直接使用 %s 5 print(s1) 6 ##显示如下 7 my name is 赵文成 8 9 Process finished with exit code 0 10 11 #———————————————————————————————————— 12 s1 = "my name is %s, age is %d" % ("赵文成",26) #使用%d 13 print(s1) 14 15 #显示如下 16 my name is 赵文成, age is 26 17 18 Process finished with exit code 0 19 #———————————————————————————————————— 20 21 s1 = "my name is %(name)s, age is %(age)d" % {"age" : 26,"name" : "赵文成"} 22 print(s1) ##使用名称指定变量引用时可以顺序不一致。 23 #显示如下: 24 my name is 赵文成, age is 26 25 26 Process finished with exit code 0 27 #———————————————————————————————————— 28 s2 = "百分数:%.2f" % (96.3456) 29 s3 = "百分数:%.2f" % (96.3446) 30 print(s2) 31 print(s3) #保留两位小数,并且会四舍五入 32 #显示如下 33 百分数:96.35 34 百分数:96.34 35 36 Process finished with exit code 0 37 #———————————————————————————————————— 38 s4 = "i am %% %(pp).2f" % {"pp": 123.425556, } #两个%才能显示 39 #显示如下: 40 i am % 123.43 41 42 Process finished with exit code 0
2.format() 方式
参数用法:
[[fill]align][sign][#][0][width][,][.precision][type]
fill 【可选】空白处填充的字符
align 【可选】对齐方式(需配合width使用)
- <,内容左对齐
- >,内容右对齐(默认)
- =,内容右对齐,将符号放置在填充字符的左侧,且只对数字类型有效。
- ^,内容居中
sign 【可选】有无符号数字
+,正号加正,负号加负;
-,正号不变,负号加负;
空格 ,正号空格,负号加负;
# 【可选】对于二进制、八进制、十六进制,如果加上#,会显示 0b/0o/0x,否则不显示
, 【可选】为数字添加分隔符,如:1,000,000
width 【可选】格式化位所占宽度
.precision 【可选】小数位保留精度
type 【可选】格式化类型
- 传入” 字符串类型 “的参数
- s,格式化字符串类型数据
- 空白,未指定类型,则默认是None,同s
- 传入“ 整数类型 ”的参数
- b,将10进制整数自动转换成2进制表示然后格式化
- c,将10进制整数自动转换为其对应的unicode字符
- d,十进制整数
- o,将10进制整数自动转换成8进制表示然后格式化;
- x,将10进制整数自动转换成16进制表示然后格式化(小写x)
- X,将10进制整数自动转换成16进制表示然后格式化(大写X)
- 传入“ 浮点型或小数类型 ”的参数
- e, 转换为科学计数法(小写e)表示,然后格式化;
- E, 转换为科学计数法(大写E)表示,然后格式化;
- f , 转换为浮点型(默认小数点后保留6位)表示,然后格式化;
- F, 转换为浮点型(默认小数点后保留6位)表示,然后格式化;
- g, 自动在e和f中切换
- G, 自动在E和F中切换
- %,显示百分比(默认显示小数点后6位)
format()应用实例如下:
# -*- coding:utf-8 -*- # Author:wencheng.zhao s1 = "my name is {},age {}".format("赵文成",26) print(s1) # 直接使用。 #显示如下: my name is 赵文成,age 26 Process finished with exit code 0 #—————————————————————————————— s2 = "my name is {},age {}".format(*["赵文成",26]) print(s2) #同样可以用这种*[]的方法传递参数 #显示如下: my name is 赵文成,age 26 Process finished with exit code 0 #—————————————————————————————— s3 = "my name is {0},age {1},!!name{0}".format("赵文成",26) print(s3) #下标的方式来引用 #显示如下: my name is 赵文成,age 26,!!name赵文成 Process finished with exit code #—————————————————————————————— s3 = "my name is {name},age {age},!!name{name}".format(name = "赵文成",age = 26) print(s3) #变量名称的方式来传递参数 #显示如下 my name is 赵文成,age 26,!!name赵文成 Process finished with exit code #—————————————————————————————— s3 = "my name is {name},age {age},!!name{name}".format(**{"name":"赵文成","age":26}) print(s3) #同样可以用**{}的方式来传递参数 #显示如下 my name is 赵文成,age 26,!!name赵文成 #—————————————————————————————— s4 = "the first number is {0[1]}, second is {1[0]}.thrid is {0[2]}..".format([11,22,33,44],[55,66,77]) print(s4) #当元素为列表等类似类型时可以直接用下标来引用 #显示如下: the first number is 22, second is 55.thrid is 33.. Process finished with exit code 0 #—————————————————————————————— s3 = "my name is {name:s},age {age:d} ".format(name = "赵文成",age = 26) print(s3) #显示如下: my name is 赵文成,age 26 Process finished with exit code #—————————————————————————————— s4 = "numbers: {:b},{:o},{:d},{:x},{:X}, {:%}".format(15, 15, 15, 15, 15, 15.87623, 2) print(s4) #显示如下: numbers: 1111,17,15,f,F, 1587.623000% Process finished with exit code 0 #—————————————————————————————— s5 = "numbers: {num:b},{num:o},{num:d},{num:x},{num:X}, {num:%}".format(num=15) print(s5) #显示如下: numbers: 1111,17,15,f,F, 1500.000000% Process finished with exit code 0 #——————————————————————————————
字符串的格式化需要记住如下方法:
1.可以顺序传入参数,2.指定名称传入参数 3.如何保留小数点后几位 4.如果出现站位符则写%% ,打印是才能打印% ,此处%号相当于一个转译。
相比%来说 format 更具有优势体现在如下:
1.支持填充任意字符
2.可以居中
3.可以二进制显示
4.没有%的特殊意义,可直接用%
5...等
三。生成器and迭代器:
1.迭代器
迭代器是访问集合元素的一种方式。迭代器对象从集合的第一个元素开始访问,直到所有的元素被访问完结束。迭代器只能往前不会后退,不过这也没什么,因为人们很少在迭代途中往后退。另外,迭代器的一大优点是不要求事先准备好整个迭代过程中所有的元素。迭代器仅仅在迭代到某个元素时才计算该元素,而在这之前或之后,元素可以不存在或者被销毁。这个特点使得它特别适合用于遍历一些巨大的或是无限的集合,比如几个G的文件,
迭代器的特点:
- 访问者不需要关心迭代器内部的结构,仅需通过next()方法不断去取下一个内容
- 不能随机访问集合中的某个值 ,只能从头到尾依次访问
- 访问到一半时不能往回退
- 便于循环比较大的数据集合,节省内存
每当调用一个__next__方法时,则会去一次值。
a = iter([1,2,3,4,5]) print(a) print(a.__next__()) print(a.__next__()) print(a.__next__()) print(a.__next__()) print(a.__next__()) ## 显示如下: <list_iterator object at 0x00000076E2BB8630> 1 2 3 4 5 Process finished with exit code 0 ##如上,如果取值次数大于总次数时,则会报错。
2.生成器
一个函数调用时返回一个迭代器,那这个函数就叫做生成器(genetator);如果一个函数包含yield语法,那这个函数就会变成生成器;
def func(): #定义一个函数 yield 1 yield 2 yield 3 yield 4 r = func() #r 获取返回值 res = r.__next__() #r调用next方法 print(res) res = r.__next__() print(res) res = r.__next__() print(res) res = r.__next__() print(res) ##获取结果如下: 1 2 3 4 Process finished with exit code 0 ##
取值时同样还会获得yield前面的值,如下:
def func(): print(1111) yield 1 print(2222) yield 2 print(3333) yield 3 r = func() res1 = r.__next__() print(res1) res2 = r.__next__() print(res2) res3 = r.__next__() print(res3) #显示如下: 1111 1 2222 2 3333 3 Process finished with exit code 0
对于如上,他的执行和对应关系如下:
3.应用实例
利用生成器的方法自定义一个函数叫做,myrange(), 实现功能,当此函数被调用时,接受一个数值参数,函数自动返回从0开始到此数值的所有值。
实现如下:
def myrange(arg): start = 0 while True: if start >arg: return else: yield start start += 1 r = myrange(4) res = r.__next__() print(res) res = r.__next__() print(res) res = r.__next__() print(res) res = r.__next__() print(res) res = r.__next__() print(res) #显示如下: 0 1 2 3 4
四。递归
如下有一串函数,分析他的执行的结果,函数如下:
def a(): r = b() print(r) def b(): r = c() return r def c(): r = d() return r def d(): return 123 a()
分析:
1.a函数中r的结果为b函数的返回值
b函数的返回值r为c函数的返回值
c函数的返回值r为d函数的返回值
d函数的返回值就是123
如上分析,a函数中的r的值为d函数的返回值123
如上为一个类似的递归,依次去执行,直到获取完最后一个返回值。
如下同样为一个递归的例子:
1 def myself (n): 2 n += 1 3 print(n) 4 if n >= 4: 5 return "end" 6 else: 7 return myself(n) ##如果满足次条件则再次执行本函数,依次递归 8 9 r = myself(0) 10 print(r) 11 12 #显示结果如下: 13 1 14 2 15 3 16 4 17 end 18 19 Process finished with exit code 0
五。模块
模块是用一系列的代码实现了某一个功能的代码集合,类似于函数式编程和面向过程编程,函数式编程则完成一个功能,其他代码用来调用即可,提供了代码的重用性和代码间的耦合。而对于一个复杂的功能来,可能需要多个函数才能完成(函数又可以在不同的.py文件中),n个 .py 文件组成的代码集合就称为模块。
模块有很多重模块,如os模块,file模块,time模块等,具体分类如下:
模块分类为3种:
- 自定义模块
- 内置模块
- 开源的第三方模块
1.模块的定义
直接创建 .py文件
-index.py
在同级目录下直接创建其他 .py文件
-index.py
-a.py
-b.py
在同级目录下直接创建目录在目录中在创建 .py的文件。
-index.py
-lib
-aaa.py
-bbb.py
2.模块的导入
所有的模块都是需要先倒入后使用,python丰富的模块,为python的程序员提供的各种操作工功能,使得python语言十分灵活和简单,当然所有的模块在使用之前都需要先倒入
python模块倒入的方法:
import module form module.xx.xx import xx form module.xx.xx import xx as xxx form module.xx.xx import * ##
导入的过程就是告诉python解释器去解释某个文件,
- 导入一个py文件,那么解释器解释该文件
- 导入一个包,解释解释该包下的__init__.py文件
如下使用sys,使用前先倒入:(sys.path所获的路径就是默认的python倒入模块时所要寻找的路径)
# import sys #先倒入 r = sys.path #再使用 for i in r: print(i) # 显示如下: /Users/wenchengzhao/PycharmProjects/s13/day5 /Users/wenchengzhao/PycharmProjects/s13 /Library/Frameworks/Python.framework/Versions/3.5/lib/python35.zip /Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5 /Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/plat-darwin /Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/lib-dynload /Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/site-packages
3.开源的第三方模块的安装
安装方式
1.使用系统自带的包管理工具安装,如: yum , apt-get ,python专门提供的pip,esayinstall等
2.下载源码包编译
下载源码
解压源码
进入目录
编译安装 python setup.py build
安装源码 python setup.py install
注:在使用源码安装时,需要使用到gcc编译和python开发环境,所以,需要先执行:
yum -y install gcc python-devel
atp-get python-dev
安装成功后会自动安装到python所能识别的环境路径下。
六.部分内置模块的使用(后续章节中会继续)
1.序列化相关模块 json && pickle
- json (JavaScript Object Notation),json用于字符串和python其他数据类型间进行转换
- pickle 用于python特有的类型,和python其他类型间的相互转换
json 和 pickle 提供的功能:
- json - dumps dump load loads
- pickle - dumps dump load loads
模块使用以及使用说明如下:
json与pickle对于 dumps dump load loads等的使用方法和使用效果相同(对于简单的数据类型),如下一json为例:
1 #s1 = "{'k1':'v1','k2':'v2'}" ##注意此处不能写成这种形式 2 s1 = '{"k1":"v1","k2":"v2"}' 3 s1_l = json.loads(s1) # json.loads使用将原先的字符串类型转换成字典类型。 4 5 print(s1_l,type(s1_l)) 6 #显示如下: 7 {'k1': 'v1', 'k2': 'v2'} <class 'dict'> 8 9 Process finished with exit code 0 10 11 #--------------------- 12 13 l1 = ["abc","1",1,"hello"] # 定义时为列表 14 l1_s = json.dumps(l1) #json的dumps方法将原先的列表类型转换成字符串类型。 15 print(l1_s,type(l1_s)) 16 #显示如下: 17 ["abc", "1", 1, "hello"] <class 'str'> 18 19 Process finished with exit code 0 20 21 #-------------------- 22 l2 = ["abc","1",1,"hello"] 23 24 json.dump(l2,open("testd.txt","w")) ##json.dump() 会直接将结果写入文件中 25 26 #结果如下: 27 #自动创建了一个文件为 testd.txt,然后里面的内容如下: 28 ["abc", "1", 1, "hello"] 29 #-------------------- 30 ss = json.load(open("testd.txt","r")) #json.load()直接打开文件 31 print(ss,type(ss)) 32 #显示如下 33 ['abc', '1', 1, 'hello'] <class 'list'> 34 35 Process finished with exit code 0
json与pickle区别:
- json - 可跨语言,只支持基本类型的序列化
- pickle - 支持所有类型的序列化,只能在python中使用
序列化使用例子:
通过天气预报借口获得天气情况,并使之可处理,实现如下:
1 ##天气相关 2 3 import requests #第三方模块,用于发送请求 4 import json 5 6 response = requests.get('http://wthrcdn.etouch.cn/weather_mini?city=北京') 7 response.encoding = 'utf-8' 8 9 dic = json.loads(response.text) #将获得的字符串类型的结果存放到字典中。 10 print(dic,type(dic)) 11 ### 12 {'status': 1000, 'desc': 'OK', 'data': {'forecast': [{'high': '高温 31℃', 'fengli': '微风级', 'type': '多云', 'low': '低温 19℃', 'fengxiang': '无持续风向', 'date': '8日星期三'}, {'high': '高温 32℃', 'fengli': '3-4级', 'type': '多云', 'low': '低温 21℃', 'fengxiang': '南风', 'date': '9日星期四'}, {'high': '高温 32℃', 'fengli': '微风级', 'type': '雷阵雨', 'low': '低温 20℃', 'fengxiang': '无持续风向', 'date': '10日星期五'}, {'high': '高温 30℃', 'fengli': '3-4级', 'type': '晴', 'low': '低温 19℃', 'fengxiang': '北风', 'date': '11日星期六'}, {'high': '高温 31℃', 'fengli': '微风级', 'type': '晴', 'low': '低温 21℃', 'fengxiang': '无持续风向', 'date': '12日星期天'}], 'yesterday': {'high': '高温 26℃', 'fl': '微风', 'date': '7日星期二', 'type': '多云', 'low': '低温 16℃', 'fx': '无持续风向'}, 'aqi': '148', 'ganmao': '各项气象条件适宜,发生感冒机率较低。但请避免长期处于空调房间中,以防感冒。', 'wendu': '28', 'city': '北京'}} <class 'dict'> 13 14 Process finished with exit code 0
2.时间相关模块 time & datetime
- time 模块提供各种操作时间的函数,一般有两种标示时间的方式,一种为时间戳的方式一种为以数组的形式表示具体使用如下:
1 import time 2 import datetime 3 4 ##返回当前系统的时间戳: 5 print(time.time()) ##显示 1465384604.16719 6 7 #———— 8 #当前系统的时间 9 print(time.ctime()) ##Wed Jun 8 19:17:35 2016 10 11 #———— 12 #将时间转换成字符串格式 13 print(time.ctime(time.time()-86440)) ## Tue Jun 7 19:18:44 2016 14 15 #---- 16 #将时间戳转换成struct_time格式 17 print(time.gmtime(time.time())) 18 #显示如下: 19 #time.struct_time(tm_year=2016, tm_mon=6, tm_mday=8, tm_hour=11, tm_min=21, tm_sec=32, tm_wday=2, tm_yday=160, tm_isdst=0) 20 21 #---- 22 #将时间戳转换成struct_time格式,但是返回的是本地时间 23 print(time.localtime(time.time())) 24 #显示如下: 25 #time.struct_time(tm_year=2016, tm_mon=6, tm_mday=8, tm_hour=19, tm_min=24, tm_sec=6, tm_wday=2, tm_yday=160, tm_isdst=0) 26 27 #---- 28 #与time.localtime()功能相反,将struc_time的格式转化为时间戳的格式。 29 print(time.mktime(time.localtime())) #显示1465385308.0 30 31 #---- 32 #time.sleep(4) #sleep 休眠等待。。。 33 34 #---- 35 #将struct_time格式转成指定的字符串格式 36 print(time.strftime("%Y-%m-%d %H:%M:%S")) ##2016-06-08 19:36:59 37 38 #---- 39 ##将字符串格式转换成struct_time格式 40 print(time.strptime("2016-01-28","%Y-%m-%d") ) 41 #显示如下: 42 #time.struct_time(tm_year=2016, tm_mon=1, tm_mday=28, tm_hour=0, tm_min=0, tm_sec=0, tm_wday=3, tm_yday=28, tm_isdst=-1)
- datetime
1 ######################### 2 import time 3 import datetime 4 print(datetime.date.today()) ##输出 2016-06-08 5 6 print(datetime.date.fromtimestamp(time.time()-86640)) #将时间戳转换成日期格式 输出:2016-06-07 7 8 now_time = datetime.datetime.now() 9 print(now_time) ##获取当前时间 显示2016-06-08 19:44:35.519973 10 11 print(now_time.timetuple()) ##返回 struct_time格式 12 #显示: time.struct_time(tm_year=2016, tm_mon=6, tm_mday=8, tm_hour=19, tm_min=45, tm_sec=49, tm_wday=2, tm_yday=160, tm_isdst=-1) 13 14 print(now_time.replace(2018,9,12)) #输出2018-09-12 19:47:56.355124,返回当前时间,但指定的值将被替换 15 16 str_to_date = datetime.datetime.strptime("21/11/16 16:30", "%d/%m/%y %H:%M") #将字符串转换成日期格式 17 print(str_to_date) 18 #显示 2016-11-21 16:30:00 19 20 new_date = datetime.datetime.now() + datetime.timedelta(days=10) #比现在加10天 21 print(new_date) 22 #显示 2016-06-18 19:52:03.079831 23 #同样的如下: 24 new_date = datetime.datetime.now() + datetime.timedelta(days=-10) #比现在减10天 25 new_date = datetime.datetime.now() + datetime.timedelta(hours=-10) #比现在减10小时 26 new_date = datetime.datetime.now() + datetime.timedelta(seconds=120) #比现在+120s
----对应的字母代表的时间格式如下:
Directive | Meaning | Notes |
---|---|---|
%a |
Locale’s abbreviated weekday name. | |
%A |
Locale’s full weekday name. | |
%b |
Locale’s abbreviated month name. | |
%B |
Locale’s full month name. | |
%c |
Locale’s appropriate date and time representation. | |
%d |
Day of the month as a decimal number [01,31]. | |
%H |
Hour (24-hour clock) as a decimal number [00,23]. | |
%I |
Hour (12-hour clock) as a decimal number [01,12]. | |
%j |
Day of the year as a decimal number [001,366]. | |
%m |
Month as a decimal number [01,12]. | |
%M |
Minute as a decimal number [00,59]. | |
%p |
Locale’s equivalent of either AM or PM. | (1) |
%S |
Second as a decimal number [00,61]. | (2) |
%U |
Week number of the year (Sunday as the first day of the week) as a decimal number [00,53]. All days in a new year preceding the first Sunday are considered to be in week 0. | (3) |
%w |
Weekday as a decimal number [0(Sunday),6]. | |
%W |
Week number of the year (Monday as the first day of the week) as a decimal number [00,53]. All days in a new year preceding the first Monday are considered to be in week 0. | (3) |
%x |
Locale’s appropriate date representation. | |
%X |
Locale’s appropriate time representation. | |
%y |
Year without century as a decimal number [00,99]. | |
%Y |
Year with century as a decimal number. | |
%z |
Time zone offset indicating a positive or negative time difference from UTC/GMT of the form +HHMM or -HHMM, where H represents decimal hour digits and M represents decimal minute digits [-23:59, +23:59]. | |
%Z |
Time zone name (no characters if no time zone exists). | |
%% |
A literal '%' character. |
3.logging模块
几乎所有程序都有记录日志的需求,并且日志中包含的信息即有正常的程序访问日志,还可能有错误、警告等信息输出,python的logging模块提供了标准的日志接口,你可以通过它存储各种格式的日志,logging的日志可以分为 debug()
, info()
, warning()
, error()
and critical() 5个级别。
更详细的日志等级:只有大于当前日志级别的信息才会被记录。
1 CRITICAL = 50 2 FATAL = CRITICAL 3 ERROR = 40 4 WARNING = 30 5 WARN = WARNING 6 INFO = 20 7 DEBUG = 10 8 NOTSET = 0
- 1.logging简单使用,将日志打印到屏幕上:
根据如下输出可知,logging的默认级别为warn,只用大于此级别的日志才能够输出:
##日志模块的测试 import logging logging.debug("debug.debug....") logging.info("info.info...") logging.warning("warn,warn.....") logging.error("err.err....") logging.critical("critical.critical...") ##显示如下 WARNING:root:warn,warn..... ERROR:root:err.err.... CRITICAL:root:critical.critical... Process finished with exit code 0
- 2.将日志文信息输出到指定的日志文件中
1 import logging 2 3 logging.basicConfig(filename="access.log",format='%(asctime)s - %(name)s - %(levelname)s -%(module)s: %(message)s',datefmt='%Y-%m-%d %H:%M:%S %p',level=10) 4 5 logging.debug('debug') 6 logging.info('info') 7 logging.warning('warning') 8 logging.error('error') 9 logging.critical('critical') 10 logging.log(10,'log') 11 ##结果: 12 #1.创建了access.log文件: 13 #2.文件中内容如下: 14 2016-06-09 10:28:59 AM - root - DEBUG -temp: debug 15 2016-06-09 10:28:59 AM - root - INFO -temp: info 16 2016-06-09 10:28:59 AM - root - WARNING -temp: warning 17 2016-06-09 10:28:59 AM - root - ERROR -temp: error 18 2016-06-09 10:28:59 AM - root - CRITICAL -temp: critical 19 2016-06-09 10:28:59 AM - root - DEBUG -temp: log
根据上面可见: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用户输出的消息
3.对log进行灵活的配置需要掌握如下知识:
logging库提供了多个组件:Logger、Handler、Filter、Formatter。Logger对象提供应用程序可直接使用的接口,Handler发送日志到适当的目的地,Filter提供了过滤日志信息的方法,Formatter指定日志显示格式。
如下定义个日志输出,分别输出到屏幕上和日志文件中,并且输出的日志级别不同。这就需要自定义hander指定输出的位置。
1 import logging 2 3 # 创建一个logger 4 logger = logging.getLogger('ZHAOWENCHENG-LOG') 5 logger.setLevel(logging.DEBUG) 6 7 # 创建一个handler(用与输出到屏幕上),设置日志级别为debug 8 ch = logging.StreamHandler() 9 ch.setLevel(logging.DEBUG) 10 11 # 创建一个handler(用与输出到日志文件中),设置日志级别为warn 12 fh = logging.FileHandler("access.log") 13 fh.setLevel(logging.WARNING) 14 # 定义一个文件格式 formatter 15 formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s') 16 17 ###将如上的定义做关联 18 #将formater与hander做关联 19 ch.setFormatter(formatter) 20 fh.setFormatter(formatter) 21 22 # 将ch 与 logger 做关联 23 logger.addHandler(ch) 24 logger.addHandler(fh) 25 26 # 用于输出的信息。 27 logger.debug('debug message') 28 logger.info('info message') 29 logger.warn('warn message') 30 logger.error('error message') 31 logger.critical('critical message')