python 基础 day5
本节内容:1、双层装饰器
2、字符串格式化
3、递归
4、生成器、迭代器
5、模块
双层装饰器
USER_INFO = {} def check_login(func): def inner(*args,**kwargs): if USER_INFO.get('is_login',None): ret = func(*args,**kwargs) return ret else: print("请登录") return inner def check_admin(func): def inner(*args,**kwargs): if USER_INFO.get('user_type',None): ret = func(*args,**kwargs) return ret else: print("无权限") return @check_login @check_admin def index(): print("index") index()
#从下晚上渲染(编译解释),@chec_admin装饰index函数,它们作为一个整体,假设这个整体的名字为nindex,那么@chec_login装饰的就是nindex。 #从上往下之行,先之行@chec_login,执行里面的func也就是执行index,index就是@check_admin和index函数,接下来执行check_admin里的func,也就是执行index 函数,那它执行的就是check_admin里的inner 函数.
字符串格式化
Python的字符串格式化有两种方式: 百分号方式、format方式
百分号的方式相对来说比较老,而format方式则是比较先进的方式,企图替换古老的方式,目前两者并存。
百分号方式
%[(name)][flags][width].[precision]typecode
- (name) 可选,用于选择指定的key
- 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;)
- %,当字符串中存在格式化标志时,需要用 %%表示一个百分号
注:Python中百分号格式化是不存在自动将整数转换成二进制表示的方式
常用格式化:
tp1 = "i am %s" % "QL" print(tp1) tp2 = "i am %s age %d" % ("QL",18) #顺序添加 print(tp2) tp3 = "i am %(name)s age %(age)d" %{"name":"QL","age":18,} #命名添加 print(tp3) tp4 = "percent %.2f" % 99.98765 print(tp4) tp5 = "i am %(pp).2f %%" %{"pp":123.2312444,} #可以命名也可以不命名 print(tp5) tp6 = "i am %.2f %%" % 123.123123 #显示百分号,需要写两个% 相当于转译 print(tp6) s = "我是%(name)s age %(age)d" % {'name':'QL','age':21} print(s) #我是QL age 21 s1 = "我是%(name)-10saa %(age) +10daa" %{'name':'QL','age':12} print(s1) #我是QL aa +12aa s2 = "hello %c------%o=====%x" % (65,15,15) #%c是asc码,%o是8进制,%x16进制 print(s2) #hello A------17=====f
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位)
常用格式化
s1 = "----{:9^20s}====={:d}====={:x}".format('QL',16,15) #x是16进制 print(s1) #----999999999QL999999999=====16=====f s2 = "sddddsssss {:.2%}".format(0.1334234) #把数字自动转换成百分比形式,并且保留2位小数 print(s2) #sddddsssss 13.34% tp1 = "i am {},age {}, {}".format("seven",18,'QL') print(tp1) #i am seven,age 18, QL tp2 = "i am {},age {}, {}".format(*["seven",18,"QL"]) #列表传递前面要加* print(tp2) tp3 = "i am {0},age {1},really {0}".format("seven",18) print(tp3) #i am seven,age 18,really seven tp4 = "i am {name},age{age},really {name}".format(name="seven",age=18) print(tp4) tp5 = "i am {0[0]}, age {0[1]}, really {0[2]}".format([1, 2, 3], [11, 22, 33]) #元素传递 print(tp5) tp6 = "i am {:s}, age {:d}, money {:f}".format("seven", 18, 88888.1) tp7 = "i am {:s}, age {:d}".format(*["seven", 18]) tp8 = "i am {name:s}, age {age:d}".format(name="seven", age=18) tp9 = "i am {name:s}, age {age:d}".format(**{"name": "seven", "age": 18}) tp10 = "numbers: {:b},{:o},{:d},{:x},{:X}, {:%}".format(15, 15, 15, 15, 15, 15.87623, 2) tpl1 = "numbers: {:b},{:o},{:d},{:x},{:X}, {:%}".format(15, 15, 15, 15, 15, 15.87623, 2) tpl2 = "numbers: {0:b},{0:o},{0:d},{0:x},{0:X}, {0:%}".format(15) tpl3 = "numbers: {num:b},{num:o},{num:d},{num:x},{num:X}, {num:%}".format(num=15)
递归
#无返回值,None def d(): return'123' def c(): r = d() return r def b(): r =c() return r def a(): r =b() print(r) a() def func(n): n +=1 if n >=4: return "end" return func(n) r = func(1) print(r)
#思考题:1*2*3*4*5*6
迭代器
迭代器是访问集合元素的一种方式。迭代器对象从集合的第一个元素开始访问,直到所有的元素被访问完结束。迭代器只能往前不会后退,不过这也没什么,因为人们很少在迭代途中往后退。另外,迭代器的一大优点是不要求事先准备好整个迭代过程中所有的元素。迭代器仅仅在迭代到某个元素时才计算该元素,而在这之前或之后,元素可以不存在或者被销毁。这个特点使得它特别适合用于遍历一些巨大的或是无限的集合,比如几个G的文件
特点:
- 访问者不需要关心迭代器内部的结构,仅需通过next()方法不断去取下一个内容
- 不能随机访问集合中的某个值 ,只能从头到尾依次访问
- 访问到一半时不能往回退
- 便于循环比较大的数据集合,节省内存
>>> a = iter([1,2,3,4,5]) >>> a <list_iterator object at 0x101402630> >>> a.__next__() 1 >>> a.__next__() 2 >>> a.__next__() 3 >>> a.__next__() 4 >>> a.__next__() 5 >>> a.__next__()
生成器
一个函数调用时返回一个迭代器,那这个函数就叫做生成器(generator);如果函数中包含yield语法,那这个函数就会变成生成器;
def func(): print("aaaa") yield 1 yield 2 print("ccc") yield 3
上述代码中:func是函数称为生成器,当执行此函数func()时会得到一个迭代器。
ret = func() r1 = ret.__next__() print(r1) r2 = ret.__next__() print(r2) r3 = ret.__next__() print(r3) #结果 aaaa 1 2 ccc 3
实例:
用生成器自定义range
def myrange(arg): start = 0 while True: if start > arg: return yield start start += 1 ret = myrange(5) r = ret.__next__() print(r) r1 = ret.__next__() print(r1) r2 = ret.__next__() print(r2) #结果 0 1 2
模块
模块 (在其他语言里叫类库)
分为三类:
1、开发者写的模块
2、第三方模块
3、自定义模块
为什么要有模块?
将代码归类
先导入,后使用(.py,或者是一个文件夹包含很多.py)
import s1 #一个.py import lib.commons #一个文件夹包含多个.py #调用 f2是s1.py里的函数,f1是lib下的commons.py里的函数 s1.f2() lib.commons.f1()
from s1 import * from s1 import f2 #s1模块名,f2是s1里的函数 f2() from lib import commons from src import commons as src_commons #如果两个文件夹里有相同模块名自可以定义别名 commons.f1()
#模块名字非常重要********* #创建模块名不要和内置模块名一样,先寻找当前目录,找到就不再往下找了,就不会调用内置模块了
查找python 路径
import sys for item in sys.path: print(item) #查找结果,我所使用的是pycharm,并建立了一个s13的项目文件,下面建立了一个day5文件夹,程序就放在这里面 C:\Users\qinling\PycharmProjects\s13\day5 C:\Users\qinling\PycharmProjects\s13 #先在当前目录找模块 在pycharm下会导入项目目录,但在Linux下是不会导入的,所以忽略此目录 C:\Users\qinling\AppData\Local\Programs\Python\Python35\python35.zip C:\Users\qinling\AppData\Local\Programs\Python\Python35\DLLs C:\Users\qinling\AppData\Local\Programs\Python\Python35\lib C:\Users\qinling\AppData\Local\Programs\Python\Python35 C:\Users\qinling\AppData\Local\Programs\Python\Python35\lib\site-packages #第三方模块存放位置 sys.path.append('E:\\') #导入E盘位置,sys.path是列表,添加python路径
推荐使用导入方法:
单模块: import 嵌套在文件夹下: from xxx import xxx from xxx import xxx as xxxxx
安装第三方模块
1、pip 安装(pip3,python3有,python2,没有)
2、源码安装:
解压进入目录
执行 python3 setup.py install
例如安装requests模块:
pip3 install requests #找到requests模块文件位置 用这个命令安装 python -m pip install requests #不用找到模块文件位置用这个命令就可以安装了
两个序列化相关的模块(把python的字典、列表等转换成字符串)
json
Json模块提供了四个功能:dumps、dump、loads、load
import json dic = {'k1':'v1'} print(dic,type(dic)) #{'k1': 'v1'} <class 'dict'> r = json.dumps(dic) #python基本数据类型转换成字符串形式 print(r,type(r)) #{"k1": "v1"} <class 'str'> s1 = '{"k1":"123"}' #里面必须是双引号,外面必须是单引号 (其他语言单引号叫字符,双引号叫字符串) r1 = json.loads(s1) #将python字符串类型转换成基本数据类型 print(r1,type(r1)) #{'k1': '123'} <class 'dict'> li = [11,22,33,] json.dump(li,open('db','w')) #先序列化再写入db文件 li = json.load(open('db','r')) #先读文件再序列化出来 print(type(li),li) #<class 'list'> [11, 22, 33]
使用json做请求获得字符串转化成字典
import json import requests response = requests.get('http://wthrcdn.etouch.cn/weather_mini?city=北京') response.encoding = 'utf-8' dic1 = json.loads(response.text) print(dic1)
pickle
只能python使用
pickle模块提供了四个功能:dumps、dump、loads、load
li = [11,222,33,] r = pickle.dumps(li) print(type(r),r) #<class 'bytes'> b'\x80\x03]q\x00(K\x0bK\xdeK!e.' result = pickle.loads(r) #转化成列表 print(result) #[11, 222, 33] pickle.dump(li,open('123','wb')) #先序列化再写入文件 re = pickle.load(open('123','rb')) #读文件,序列化后输出 print(re) #[11, 222, 33]
两者区别与优缺点:
json 只能处理基本的数据类型,更加适合跨语言,字符串,如果是一个自己的写的类就不能转换
pickel 支持任何类型,适合对python的所有类型操作,仅适用于python,python版本不同可能会出现问题
time 模块 (http://www.cnblogs.com/alex3714/articles/5161349.html)
常用
import time print(time.time()) #1970年开始计时到现在的系统时间戳 #1465123123.342 print(time.ctime()) #当前时间 #Sun Jun 5 18:38:43 2016 print(time.ctime(time.time()-86400)) #Sat Jun 4 18:38:43 2016 print(time.gmtime()) #time.struct_time(tm_year=2016, tm_mon=6, tm_mday=5, tm_hour=10, tm_min=38, tm_sec=43, tm_wday=6, tm_yday=157, tm_isdst=0) t_obj = time.gmtime() print(t_obj.tm_year,t_obj.tm_mon,t_obj.tm_mday) #2016 6 5 print(time.localtime()) #获取本地时间,本地用哪个时区就获取哪个时区的 #time.struct_time(tm_year=2016, tm_mon=6, tm_mday=5, tm_hour=18, tm_min=40, tm_sec=41, tm_wday=6, tm_yday=157, tm_isdst=0) print(time.mktime(t_obj)) #把时间对象转成时间戳 #1465094462.0 time.sleep(4) print("-------") tm = time.strftime("%Y-%m-%d %H:%M:%S",time.localtime()) #常用 将字符串格式转成格式化形式 print(tm) #2016-06-05 18:41:27 tm1 = time.strptime("2016-05-6 15:06","%Y-%m-%d %H:%M") print(tm1) #time.struct_time(tm_year=2016, tm_mon=5, tm_mday=6, tm_hour=15, tm_min=6, tm_sec=0, tm_wday=4, tm_yday=127, tm_isdst=-1)
datetime
常用
import datetime print(datetime.date.today()) #2016-06-05 tm2 = datetime.datetime.now() # 现在的时间 print(tm2) #2016-06-05 18:42:58.458000 print(datetime.datetime.now() + datetime.timedelta(days=10)) #比现在加10天 #2016-06-15 18:42:58.458000 current_time = datetime.datetime.now() print(current_time.replace(2015,5)) #直接回到某个时间 #2015-05-05 18:42:58.458000 time_obj = current_time.replace(2015,5) print(current_time==time_obj)
time &datetime
import time import datetime print(time.clock()) #返回处理器时间,3.3开始已废弃 print(time.process_time()) #返回处理器时间,3.3开始已废弃 print(time.time()) #返回当前系统时间戳 print(time.ctime()) #输出Tue Jan 26 18:23:48 2016 ,当前系统时间 print(time.ctime(time.time()-86640)) #将时间戳转为字符串格式 print(time.gmtime(time.time()-86640)) #将时间戳转换成struct_time格式 print(time.localtime(time.time()-86640)) #将时间戳转换成struct_time格式,但返回 的本地时间 print(time.mktime(time.localtime())) #与time.localtime()功能相反,将struct_time格式转回成时间戳格式 #time.sleep(4) #sleep print(time.strftime("%Y-%m-%d %H:%M:%S",time.gmtime()) ) #将struct_time格式转成指定的字符串格式 print(time.strptime("2016-01-28","%Y-%m-%d") ) #将字符串格式转换成struct_time格式 #datetime module print(datetime.date.today()) #输出格式 2016-01-26 print(datetime.date.fromtimestamp(time.time()-864400) ) #2016-01-16 将时间戳转成日期格式 current_time = datetime.datetime.now() # print(current_time) #输出2016-01-26 19:04:30.335935 print(current_time.timetuple()) #返回struct_time格式 #datetime.replace([year[, month[, day[, hour[, minute[, second[, microsecond[, tzinfo]]]]]]]]) print(current_time.replace(2014,9,12)) #输出2014-09-12 19:06:24.074900,返回当前时间,但指定的值将被替换 str_to_date = datetime.datetime.strptime("21/11/06 16:30", "%d/%m/%y %H:%M") #将字符串转换成日期格式 new_date = datetime.datetime.now() + datetime.timedelta(days=10) #比现在加10天 new_date = datetime.datetime.now() + datetime.timedelta(days=-10) #比现在减10天 new_date = datetime.datetime.now() + datetime.timedelta(hours=-10) #比现在减10小时 new_date = datetime.datetime.now() + datetime.timedelta(seconds=120) #比现在+120s print(new_date)
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. |
logging模块
python的logging模块提供了标准的日志接口,通过它存储各种格式的日志,logging的日志可以分为 debug()
, info()
, warning()
, error()
and critical() 5个级别
import logging logging.warning("user [alex] attempted wrong password more than 3 times") logging.critical("server is down") #输出 WARNING:root:user [alex] attempted wrong password more than 3 times CRITICAL:root:server is down
默认的日志格式为:
日志级别:Logger名称:用户输出消息。
看一下这几个日志级别分别代表什么意思
Level | When it’s used |
---|---|
DEBUG |
Detailed information, typically of interest only when diagnosing problems. |
INFO |
Confirmation that things are working as expected. |
WARNING |
An indication that something unexpected happened, or indicative of some problem in the near future (e.g. ‘disk space low’). The software is still working as expected. |
ERROR |
Due to a more serious problem, the software has not been able to perform some function. |
CRITICAL |
A serious error, indicating that the program itself may be unable to continue running. |
把日志写到文件里
import logging logging.basicConfig(filename='example.log',level=logging.INFO) logging.debug('This message should go to the log file') logging.info('So should this') logging.warning('And this, too')
其中level=loggin.INFO意思是,把日志纪录级别设置为INFO,只有日志是INFO或比INFO级别更高的日志才会被纪录到文件里,在这个例子, 第一条日志是不会被纪录的,如果希望记录debug的日志,那把日志级别改成DEBUG就行了。
给日志加上时间
import logging logging.basicConfig(format='%(asctime)s %(message)s', datefmt='%m/%d/%Y %I:%M:%S %p') logging.warning('is when this event was logged.') #输出 12/12/2010 11:46:36 AM is when this event was logged.
灵活配置日志级别,日志格式,输出位置
import logging logging.basicConfig(level=logging.DEBUG, format='%(asctime)s %(filename)s[line:%(lineno)d] %(levelname)s %(message)s', datefmt='%a, %d %b %Y %H:%M:%S', filename='/tmp/test.log', filemode='w') logging.debug('debug message') logging.info('info message') logging.warning('warning message') logging.error('error message') 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
日志级别等级CRITICAL > ERROR > WARNING > INFO > DEBUG > NOTSET),
可见在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 用户输出的消息
若要对logging进行更多灵活的控制,有必要了解下:
Logger,Handler,Formatter,Filter
上述几个例子中我们了解到了logging.debug()、logging.info()、logging.warning()、logging.error()、logging.critical()(分别用以记录不同级别的日志信息),
logging.basicConfig()(用默认日志格式(Formatter)为日志系统建立一个默认的流处理器(StreamHandler),
设置基础配置(如日志级别等)并加到root logger(根Logger)中)这几个logging模块级别的函数,
另外还有一个模块级别的函数是logging.getLogger([name])(返回一个logger对象,如果没有指定名字将返回root logger)
#coding:utf-8 import logging # 创建一个logger logger = logging.getLogger() logger1 = logging.getLogger('mylogger') logger1.setLevel(logging.DEBUG) logger2 = logging.getLogger('mylogger') logger2.setLevel(logging.INFO) logger3 = logging.getLogger('mylogger.child1') logger3.setLevel(logging.WARNING) logger4 = logging.getLogger('mylogger.child1.child2') logger4.setLevel(logging.DEBUG) logger5 = logging.getLogger('mylogger.child1.child2.child3') logger5.setLevel(logging.DEBUG) # 创建一个handler,用于写入日志文件 fh = logging.FileHandler('/tmp/test.log') # 再创建一个handler,用于输出到控制台 ch = logging.StreamHandler() # 定义handler的输出格式formatter formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s') fh.setFormatter(formatter) ch.setFormatter(formatter) #定义一个filter #filter = logging.Filter('mylogger.child1.child2') #fh.addFilter(filter) # 给logger添加handler #logger.addFilter(filter) logger.addHandler(fh) logger.addHandler(ch) #logger1.addFilter(filter) logger1.addHandler(fh) logger1.addHandler(ch) logger2.addHandler(fh) logger2.addHandler(ch) #logger3.addFilter(filter) logger3.addHandler(fh) logger3.addHandler(ch) #logger4.addFilter(filter) logger4.addHandler(fh) logger4.addHandler(ch) logger5.addHandler(fh) logger5.addHandler(ch) # 记录一条日志 logger.debug('logger debug message') logger.info('logger info message') logger.warning('logger warning message') logger.error('logger error message') logger.critical('logger critical message') logger1.debug('logger1 debug message') logger1.info('logger1 info message') logger1.warning('logger1 warning message') logger1.error('logger1 error message') logger1.critical('logger1 critical message') logger2.debug('logger2 debug message') logger2.info('logger2 info message') logger2.warning('logger2 warning message') logger2.error('logger2 error message') logger2.critical('logger2 critical message') logger3.debug('logger3 debug message') logger3.info('logger3 info message') logger3.warning('logger3 warning message') logger3.error('logger3 error message') logger3.critical('logger3 critical message') logger4.debug('logger4 debug message') logger4.info('logger4 info message') logger4.warning('logger4 warning message') logger4.error('logger4 error message') logger4.critical('logger4 critical message') logger5.debug('logger5 debug message') logger5.info('logger5 info message') logger5.warning('logger5 warning message') logger5.error('logger5 error message') logger5.critical('logger5 critical message'
同时把log打印在屏幕和文件日志里
The logging library takes a modular approach and offers several categories of components: loggers, handlers, filters, and formatters.
- Loggers expose the interface that application code directly uses.
- Handlers send the log records (created by loggers) to the appropriate destination.
- Filters provide a finer grained facility for determining which log records to output.
- Formatters specify the layout of log records in the final output.
import logging #create logger logger = logging.getLogger('TEST-LOG') logger.setLevel(logging.DEBUG) # create console handler and set level to debug ch = logging.StreamHandler() ch.setLevel(logging.DEBUG) # create file handler and set level to warning fh = logging.FileHandler("access.log") fh.setLevel(logging.WARNING) # create formatter formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s') # add formatter to ch and fh ch.setFormatter(formatter) fh.setFormatter(formatter) # add ch and fh to logger logger.addHandler(ch) logger.addHandler(fh) # 'application' code logger.debug('debug message') logger.info('info message') logger.warn('warn message') logger.error('error message') logger.critical('critical message')