• 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:python2day6
    4 C:UsersAdministratorAppDataLocalProgramsPythonPython35-32python35.zip
    5 C:UsersAdministratorAppDataLocalProgramsPythonPython35-32DLLs
    6 C:UsersAdministratorAppDataLocalProgramsPythonPython35-32lib
    7 C:UsersAdministratorAppDataLocalProgramsPythonPython35-32
    8 C:UsersAdministratorAppDataLocalProgramsPythonPython35-32libsite-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:python2day6s2.py
    7 C:python2day6
    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'x80x03]qx00(Kx01Kx02Kx03Kx04Kx01Kx02x88x87qx01e.' <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.6Scripts

    运行: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
  • 相关阅读:
    [恢]hdu 2391
    [恢]hdu 2352
    [恢]hdu 2393
    [恢]hdu 1868
    [恢]hdu 1279
    [恢]hdu 2086
    [恢]hdu 1405
    [恢]hdu 2088
    [恢]hdu 2106
    [恢]hdu 2537
  • 原文地址:https://www.cnblogs.com/evilliu/p/5576271.html
Copyright © 2020-2023  润新知