day5--<装饰器、模块、字符串格式化、生成器、迭代器>logging模块




本节大纲:

双层装饰器:
一个函数可以被多层装饰器进行装饰,函数渲染(编译)从下到上,函数执行从上到下。
如下程序:

 1 #!/usr/bin/env python
 2 #-*-coding:utf-8-*-
 3 # author:liumeide
 4 
 5 # USERINOF={'islogin':True}
 6 USERINOF={'user_type':'2','islogin':True}
 7 def login(func):
 8     def inner_1(*args,**kwargs):
 9         if USERINOF.get('islogin',None):
10             ret=func()
11             return ret
12         else:
13             print('login first!')
14     return  inner_1
15 def check_user(func):
16     def inner(*args,**kwargs):
17         if USERINOF.get('islogin',None)==True and USERINOF.get('user_type',None)=='2':
18             ret=func()
19             return ret
20         else:
21             print('permission deny!!')
22     return inner
23 @login
24 @check_user
25 def index():
26     print('index')
27 
28 index()
 多层装饰器该如何理解呢?

 上面的函数的可以执行顺序可以理解为:

首先:函数login、check_user、index加载到内存。在调用index函数的时候,执行index函数,因为index函数被check_user函数装饰,所以把check_user函数的内的inner函数体重新赋值给index,index函数体被当做
参数传入check_user函数。当满足inner函数的条件的时候被执行,新的函数index函数的函数体inner被login函数的所装饰,也就是说inner函数被重新赋值给inner_1函数。也就是说最后调用执行index()顺序:
先执行inner_1函数体----->在执行inner函数体-->在执行index原先的函数体。
多层装饰器以此类推,同样的原理。三层以上的装饰器很少使用。
二:字符串格式化:
%[(name)][flags][width].[precision]typecode
%号初始化字符串:
顺序传入参数。
执行名称传入参数
保留小数点后几位
当有占位符的时候 需要%%输出%如果没有占位符需要只写一个%在占位符的时候类似一个转义的意思。
1:
1 print('name:%s,age:%s'%('evil','22'))
2 
3 name:evil,age:22
普通字符串的初始化,需要传入的实参和占位符的个数保持一致。
(name):按名字进行取值。

 

 2:可以根据占位的name的key,根据后面的字典对应的value进行传入来进行传入实参。
1 print("Name:%(name)s"%{'name':'ok'})
2 Name:ok
3: flags一般和width宽度来一起配合使用,如果单纯的使用flags并没什么效果。很少使用这个功能。
1 print("qqqq%(name)+s"%{'name':'ok'})
2 qqqqok
2个一起配合使用:+10表示右对齐,字符串ok占用10个字符。右对齐;正数前加正好,负数前加负号
1 print("qqqq%(name)+10s"%{'name':'ok'})
2 qqqq        ok

  -号表示左对齐。左对齐;正数前无符号,负数前加负号;

空格    右对齐;正数前加空格,负数前加负号;

0        右对齐;正数前无符号,负数前加负号;用0填充空白处; 

 .precision   可选,小数点后保留的位数

但是没有居中的功能。

1 print("qqqq%(name)-10sqqq"%{'name':'ok'})
2 qqqqok        qqq
 
print("%+10d" % 10)
       +10


1 print("%-10d" %10)
2 10        

 
1 print("%04d" % 5)
2 0005

1 print("%04d" % -5)
2 -005
1 print("% 4d" % 5)
2    5

 

1 print("%.2f" % 1.225)
2 1.23

 

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;)

  %,当字符串中存在格式化标志时,需要用 %%表示一个百分号

但是没有将整数转换成二进制功能。

1 print('%%%d'%5)
2 %5
1 print('------%c-----%o-------%x'%(65,15,15))
2 ------A-----17-------f

 

format函数初始化字符串:
[[fill]align][sign][#][0][width][,][.precision][type]
1 print('adad{0}adadada{0}dada{1}'.format(1,2))
2 adad1adadada1dada2
1 print('adad{name}adadada{age}'.format(name='OK',age=22))
2 adadOKadadada22

 

居中功能并用a填充宽度为10. 
1 print('adad{name:a^10s}adadada{age}'.format(name='OK',age=22))
2 adadaaaaOKaaaaadadada22
左对齐<
1 print('adad{name:a<10s}adadada{age}'.format(name='OK',age=22))
2 adadOKaaaaaaaaadadada22

 右对齐>

1 print('adad{name:a>10s}adadada{age}'.format(name='OK',age=22))
2 adadaaaaaaaaOKadadada22

 

转化百分比
print('this is {:%}'.format(0.2222))
this is 22.220000%
支持整数转化二进制输出:
1 print("---{0:d}----{0:b}---{0:o}--{1:%}".format(15,0.2))
2 ---15----1111---17--20.000000%
三:生成器和迭代器
具有生成一定条件数据的能力的对象叫做生成器。
具有取数据的能力叫做迭代器。
在进行处理大数据的时候,用生成器会降低内存的消耗,每一次取值生成一次,在下次取值的时候,内存会回收该值,避免了浪费内存。
其中filter函数和map函数返回的对象就是生成器。比如xrange函数返回的对象也是生成器。
1 a=[1,2,31,4]
2 f=filter(lambda a:a>3,a)
3 
4 for i in f:
5     print(i)
6 print(f)
7 31
8 4
9 <filter object at 0x004C5B50>

 

生成器本身由函数创造的,如何把普通的函数转成生成器呢?
如果函数体内包含关键字yield 时这个函数就是生成器。
1 def fun():
2     print(111)
3     yield 1
4 fun()
5 print(fun())
6 <generator object fun at 0x00584780>

 在调用函数的fun()时候并不执行函数。只有去取这个对象的时候进行生成。

 1 def fun():
 2     yield 1
 3     yield 2
 4     yield 3
 5 fun()
 6 for i in fun():
 7     print('__%s'%i)
 8 print(fun())
 9 __1
10 __2
11 __3
12 <generator object fun at 0x004E4780>

 当for循环执行时,执行函数体。第一次的时候,去函数func找yield 对应的值1 赋值给i输出,第二次从第一次的位置下一个的yield的值为2取值并赋值给i,直到取到所有的yield的结束循环。每一次取值生成对应的对象。

上面的函数fun是生成器而生成的结果fun()是迭代器,也就说对象具有可以被迭代,在迭代时候执行next方法取值,只能从前往后取值,

练习:基于生成器生成range功能。
 1 def myrange(args):
 2     st=0
 3     while True:
 4         if st >args:
 5             return
 6         yield st
 7         st+=1
 8 ret=myrange(9)
 9 for i in ret:
10     print(i)
11 0
12 1
13 2
14 3
15 4
16 5
17 6
18 7
19 8
20 9

 

四:函数递归。执行本身的函数体,当满足一定条件退出,并把最后执行的结果返回给上个函数,如果没有条件限制会无限执行下去。
1 def fun(x):
2     x+=1
3     if x>3:
4         return 1
5     return fun(x)
6 t=fun(1)
7 print(t)
8 1

 执行3次fun(x)函数。循环执行多次相同的函数体。

 

 

练习:实现累乘功能,比如输入3  实现3*2*1

1 def fun(x):
2     if x==1:
3         return 1
4     return x*fun(x-1)
5 print(fun(3))
6 6

 

五:模块
分类:内置模块、第三方模块、自定义模块。在python中叫模块其他语言叫类库。
使用模块:先import 导入后使用。
存在方式:.py文件。或者一个文件夹里有多个.py文件组成的一个模块。
自定义模块导入:

目录之间用.表示

如果同一级不通模块导入相同的方法该如何区分呢???

1:通过相对路径来区分

request模块调用上面的2个co模块。如果路径层级不多可以这么写 如果层级过多呢?调用次数过多呢?

1 import lib.co
2 import common.co
3 common.co.login()
4 lib.co.login()
5 common OK
6 lib OK

 

简单的方法 将导入的模块进行别名操作:

1 from lib import  co as f1
2 from  common import  co as f2
3 f1.login()
4 f2.login()
5 lib OK
6 common OK

 

下面的方法是我们经常用的。

模块的意义:便于管理代码。不同的功能的代码进行归类。

模块导入的依据:

1 import sys
2 print(sys.path)
3 C:\python2\day6
4 C:\Users\Administrator\AppData\Local\Programs\Python\Python35-32\python35.zip
5 C:\Users\Administrator\AppData\Local\Programs\Python\Python35-32\DLLs
6 C:\Users\Administrator\AppData\Local\Programs\Python\Python35-32\lib
7 C:\Users\Administrator\AppData\Local\Programs\Python\Python35-32
8 C:\Users\Administrator\AppData\Local\Programs\Python\Python35-32\lib\site-packages

 

sys.path是一个路径的列表。默认python 有限搜索当前py文件的目录依次搜索。所以当我们自定义模块时候可以有2种方式让python 找到我们定义的模块:

1:把自定义模块加入这个列表(append())

2:把自定义的模块加入上面的目录之中。

这样在导入模块的时候不会出现:ImportError: No module named 'xxx'

那怎么找出自己模块所在目录呢?

1 import os
2 print(os.path.abspath(__file__))
3 print(os.path.dirname(os.path.abspath(__file__)))
4 print(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
5 
6 C:\python2\day6\s2.py
7 C:\python2\day6
8 C:\python2

 

根据自己需求将自己的变量导入sys.path即可。

模块的名称:不要和系统的内置模块的名字冲突。

第三方模块:1:pip进行安装

      2:源码进行安装。

安装第三方模块:requests

pip install requests

常用模块介绍:

json模块:

常用函数dums()、dum();loads()、load()

对于加s参数和不加s参数区别:

加s的是直接可以对python 的数据转换成json串(dums())或者直接将json串转换成python能识别的数据类型。而不加s的是将python的数据转换成json串并将json串写入文件中,或者将文件中的json串转换成python的基本数据。

1 data=[1,2,3,4,(1,2,True)]
2 obl=json.dumps(data)
3 with open('data.txt','w') as f1:
4     f1.write(obl)
5 <class 'str'> [1, 2, 3, 4, [1, 2, true]]

 

 

如果需要写入需要操作文件才能写入。

1 data=[1,2,3,4,(1,2,True)]
2 obl=json.dumps(data)
3 t_load=json.loads(obl,encoding='utf8')
4 print(type(t_load),t_load)
5 <class 'list'> [1, 2, 3, 4, [1, 2, True]]

 

在将python基本数据类型进行json转换的时候,会将python的一些数据类型或者相应的值进行转换,比如上面的python的元组转换json时候变为列表。True变为 true。

转换表如下:

跨语言平台常用该模块。该模块可以将python的基本数据类型(列表、字典)转换成字符串----序列化。也可以将字符串形式的python 类型字符创转换成对应的数据类型(列表、字典)--反序列化。

 

1 import json
2 list_1=[1,2,3,4,]
3 # json.dump(list_1,open('json.txt','w'))
4 obj=json.load(open('json.txt','r'))
5 print(obj)
6 [1, 2, 3, 4]
pickle模块:可以将非python数据类型的数据进行序列化和反序列化。存储方式是二进制。所以要以wb或者rb进行相关的dums和loads
1 import pickle
2 a='aa'
3 pickle.dump(bytes(a,encoding='utf-8'),open('pickle.txt','wb'))

 pickle.dumps()将相应的数据类型转换成字节。如果不指定编码,python解释器会用默认编码进行处理。

1 import pickle
2 data=[1,2,3,4,(1,2,True)]
3 t=pickle.dumps(data)
4 print(t,type(t))
5 b'\x80\x03]q\x00(K\x01K\x02K\x03K\x04K\x01K\x02\x88\x87q\x01e.' <class 'bytes'>

 

1 import pickle
2 a='aa'
3 # pickle.dump(bytes(a,encoding='utf-8'),open('pickle.txt','wb'))
4 t=pickle.load(open('pickle.txt','rb'))
5 s=str(t,encoding='utf-8')
6 print(s)
7 aa

 

import pickle
data=[1,2,3,4,(1,2,True)]
t=pickle.dumps(data)
t_load=pickle.loads(t)
print(t_load,type(t_load))
[1, 2, 3, 4, (1, 2, True)] <class 'list'>

 

 在Django中会用到经常用到pickle模块。

requests模块:属于第三方模块需要进行手动安装(pip  install requests)

进入python安装目录:E:\python3.6\Scripts

运行:pip.exe install request

import  requests
import json
res=requests.get("http://wthrcdn.etouch.cn/weather_mini?city=北京")
res.encoding='utf-8'
print(type(res))
dict_1=json.loads(res.text)
print(dict_1)

 time模块和datatime 模块

获取本地准确时间:

1 import time
2 print( time.strftime("%Y-%m-%d %H:%M:%S",time.localtime(time.time())))
3 
4 2016-09-23 21:50:45

 

time模块:首先了解下

时间戳的概念:时间戳是指格林威治时间1970年01月01日00时00分00秒(北京时间1970年01月01日08时00分00秒)起至现在的总秒数。

1:获取本地时间戳

1 import  time,datetime
2 print(time.time())##获取本地的时间的时间戳。
3 1465714711.3878157

 2:获取本地时间。

1 import  time,datetime
2 print(time.ctime())
3 Sun Jun 12 15:02:33 2016

 

 3:获取本地时间的时间struct_time格式。

1 print(time.localtime())
2 time.struct_time(tm_year=2016, tm_mon=6, tm_mday=12, tm_hour=15, tm_min=27, tm_sec=2, tm_wday=6, tm_yday=164, tm_isdst=0)

 

4:将时间戳转换成字符串时间 

1 import  time,datetime
2 print(time.ctime(time.time()))
3 Sun Jun 12 15:05:13 2016

 

 5:将时间戳转成struct_time格式。time.mktime把struct_time格式的时间转换成时间戳。

1 print(time.mktime(time.gmtime()))
2 1465687430.0

 

struct_time格式是元组,可以进行相关取值。

这种获取的struct_time格式是hour不是本地地时间的hour,查时区的8小时。也就是说time.time()格林威治时间戳。换成time.localtime()

1 import  time,datetime
2 print(time.gmtime(time.time()))
3 time.struct_time(tm_year=2016, tm_mon=6, tm_mday=12, tm_hour=7, tm_min=11, tm_sec=44, tm_wday=6, tm_yday=164, tm_isdst=0)

 

1 print(time.localtime())
2 time.struct_time(tm_year=2016, tm_mon=6, tm_mday=12, tm_hour=16, tm_min=50, tm_sec=52, tm_wday=6, tm_yday=164, tm_isdst=0)

5:将struct_time格式转换成指定字符串时间格式

1 import  time,datetime
2 print(time.strftime("%Y-%m-%d %H:%M:%S",time.gmtime(time.time())))
3 2016-06-12 07:14:47

 

注意:也就是说首先需要获取时间戳然后转换成struct_time格式然后转换成你想要的时间格式。

可以把指定的时间格式字符串转换成struct_time格式然后在转换成时间戳。

1 print(time.strptime('2016-06-12 07:14:47',"%Y-%m-%d %H:%M:%S"))
2 time.struct_time(tm_year=2016, tm_mon=6, tm_mday=12, tm_hour=7, tm_min=14, tm_sec=47, tm_wday=6, tm_yday=164, tm_isdst=-1)

 

1 print(time.mktime(time.strptime('2016-06-12 07:14:47',"%Y-%m-%d %H:%M:%S")))
2 1465686887.0

datetime模块:

返回当前时间格式xx-xx-xx

1 print(datetime.datetime.today())
2 2016-06-12 15:25:21.323805

可以用切割获取我们想要的格式:

1 TIME=datetime.datetime.today()
2 TIME_INT=str(TIME).split('.')[0]
3 print(TIME_INT)
4 2016-06-12 16:40:00

将时间戳转换成时间字符串

1 print(datetime.datetime.fromtimestamp(time.time()))
2 2016-06-12 15:49:05.047899

 输出当前时间:

1 print(datetime.datetime.now())
2 2016-06-12 16:43:07.611796

 

也可以将时间格式的转换成字符换进行进行切割出大约的时间(因为毫秒去掉)

将时间戳转换成struct_time格式 如下输出不存在时区问题。

1 TIME=datetime.datetime.now()
2 print(TIME.timetuple())
3 time.struct_time(tm_year=2016, tm_mon=6, tm_mday=12, tm_hour=16, tm_min=46, tm_sec=35, tm_wday=6, tm_yday=164, tm_isdst=-1)

 将字符串转化成日期格式。

1 str_to_date = datetime.datetime.strptime("21/11/06 16:30", "%d/%m/%y %H:%M")
2 2006-11-21 16:30:00

时间的加减:

1 new_date = datetime.datetime.now() + datetime.timedelta(days=10)##比现在时间加10天。
2 print(new_date)
3 2016-06-22 17:29:11.435878

 

1 new_date = datetime.datetime.now() + datetime.timedelta(days=-10)## 比现在减10天。
2 print(new_date)
3 2016-06-02 17:30:33.124046

 

1 new_date = datetime.datetime.now() + datetime.timedelta(hours=-10)#比现在减10小时。
2 print(new_date)

 

1 new_date = datetime.datetime.now() + datetime.timedelta(seconds=120)#比现在加120秒。
2 print(new_date)
3 2016-06-12 17:36:07.311463

 

模块:logging

 

首先创建logging实例。然后创建handler,分两种 一种输出到文件中 Filehandler,一种输出到终端的Streamhandler.分别为这两种handler指定输出格式setformatter

然后将这2种handler添加(add)到logging实例中。该实例就有输出到文件和终端的日志信息的属性。

实际例子:

 1 import logging
 2 def logsystem(x):
 3     log=logging.getLogger("mylog")##定义一个logging的实例log
 4     log.setLevel(logging.INFO) #设置全局日志级别,如果handler的日志级别低于INFO,不会输出日志信息。
 5 
 6     fl=logging.FileHandler(x,encoding='utf-8')##设置一个文件输出的Filehandler.可以指定输出文件的编码,写入方式默认a追加,可以指定。
 7     fl.setLevel(logging.ERROR)#设置输出级别ERROR
 8 
 9     con=logging.StreamHandler()#设置终端Streamhandler.
10     con.setLevel(logging.INFO)#设置输出日志信息级别。
11 
12     Formate=logging.Formatter(('%(asctime)s - %(name)s - %(levelname)s - %(message)s'))#设置输出日志格式。主要asctime是输出时间。name是上面logging实例名字"mylog"。message是在调用的时候输入的日志信息。
13     fl.setFormatter(Formate)#分别给各个handler设置日志格式。
14     con.setFormatter(Formate)
15 
16     log.addHandler(fl)#给logging实例log添加handler属性。
17     log.addHandler(con)
18     return log#该函数的返回值是logging实例。

 

 

1: logging.getLogger([name])

返回一个logger实例,如果没有指定name,返回root logger。只要name相同,返回的logger实例都是同一个而且只有一个,即name和log实例是一一对应的。这意味着,无需把logger实例在各个模块中传递。

只要知道name,就能得到 同一个logger实例

2:Log.setLevel(lvl)
设置logger的level, level有以下几个级别:NOTSET < DEBUG < INFO < WARNING < ERROR < CRITICAL

如果把looger的级别设置为INFO, 那么小于INFO级别的日志都不输出, 大于等于INFO级别的日志都输出

 

1 log.debug("foobar")    # 不输出 
2 log.info("foobar")        # 输出
3 log.warning("foobar") # 输出
4 log.error("foobar")      # 输出
5 log.critical("foobar")    # 输出 

3:Log.addHandler(hdlr)
log可以雇佣handler来帮它处理日志, handler主要有以下几种:
StreamHandler: 输出到控制台
FileHandler:   输出到文件
handler还可以设置自己的level以及输出格式。

 

logging.basicConfig([**kwargs])
* 这个函数用来配置root logger, 为root logger创建一个StreamHandler, 设置默认的格式。
   
* 这些函数: logging.debug()、logging.info()、logging.warning()、
   logging.error()、logging.critical() 如果调用的时候发现root logger没有任何 
   handler, 会自动调用basicConfig添加一个handler
* 如果root logger已有handler, 这个函数不做任何事情

使用basicConfig来配置root logger的输出格式和level:

1 import logging
2 logging.basicConfig(format='%(levelname)s:%(message)s', level=logging.DEBUG)
3 logging.debug('This message should appear on the console') 

完整的例子:

 1 class Logger:
 2     '''
 3     功能:该类主要是日志实例的创建。
 4     :param:filename:文件名字。
 5     :param:logger:创建日志实例的名字。注意这个是变量。而且必须要有的变量。否则日志文件内容会乱。
 6     :return:Log返回一个创建的log的实例。
 7     '''
 8     def __init__(self,filename,logger):
 9         self.filename=filename
10         self.logger=logger
11     def log_in(self):
12         Log=logging.getLogger(self.logger)
13         Log.setLevel(logging.INFO)
14         f1=logging.FileHandler(os.path.join(LOG_DIR,self.filename),encoding='utf-8')
15         f1.setLevel(logging.INFO)
16         formate=logging.Formatter(('%(asctime)s - %(name)s - %(levelname)s - %(message)s'))
17         f1.setFormatter(formate)
18         Log.addHandler(f1)
19         return  Log

 

posted @ 2016-06-11 23:48  evil_liu  阅读(402)  评论(0编辑  收藏  举报