day05 Python多层装饰器、模块、序列化、字符串格式化、生成器和迭代器、递归、time、datetime模块、logging模块
一、多层装饰器
需求如下:
程序运行时需判断当前是否有用户登录,以及当前登录的用户名是否为管理员账户,但有的函数只需判断当前是否有用户登录就可以,有的函数两个都需要判断,所以将这两个判断分开写成两个装饰器,在需要判断时直接使用相应的一个或两个装饰器即可,具体代码如下:
#!/usr/bin/env python # -*- coding:utf-8 -*- #保存当前登录的账户名及账户类型(管理员为2,普通用户为1) USER_INFO = {} def check_login(func): """ 判断当前是否有用户登录的装饰器 :param func: :return: """ def inner(*args, **kwargs): if USER_INFO.get('is_login', None): ret = func(*args, **kwargs) return ret else: return ('请登录') return inner def check_admin(func): """ 装饰器:用来判断当前所登录用户的类型是普通账户还是管理员账户 :param func: :return: """ def inner(*args, **kwargs): if USER_INFO.get('user_type', None) == 2: ret = func(*args, **kwargs) return ret else: return ('无权限查看') return inner def login(): """ 登录函数 :return: """ username = input("请输入用户名: ") password = input("请输入密码:") if username == 'ordinary' and password == '123': USER_INFO['is_login'] = True USER_INFO['user_type'] = 1 return ("欢迎访问") elif username == 'admin' and password == '456': USER_INFO['is_login'] = True USER_INFO['user_type'] = 2 return ("欢迎管理员登录") else: return "用户名或密码错误" @check_login @check_admin def index_admin(): """ 管理员的功能 管理员的功能需要判断当前是否有用户登录,以及当前登录的用户是否为管理员账户,所以这里要用到两个装饰器 :return: """ return ('管理员的功能') @check_login def index_ordinary(): """ 普通账户的功能 :return: """ return "普通用户的功能" def run(): """ 前端 :return: """ dict_choice = {'1':login,'2':index_admin,'3':index_ordinary} while True: print("1: 登录\n2: 管理员功能\n3: 普通用户功能") user_choice = input("请输入项目编号(输入'q'结束程序):") if user_choice in dict_choice.keys(): res = dict_choice[user_choice]() print(res) elif user_choice == 'q': break else: print("你的输入有误,请重新输入") if __name__ == '__main__': run()
双层装饰器执行图解:
二、模块
Python的模块分为三类:
1、内置模块(python自带的比如os、file等模块)
2、自定义模块,自己写的模块
3、第三方模块
导入模块的方法:
单模块: import xxx 嵌套在文件夹下: from xxx import xxx(*) #导入某模块下的指定模块(或全部模块)
from xxx import xxx as ooo #导入指定模块并给他设置别名
三、序列化(json和pickle)
Python的序列化有两个模块可以实现,json和pickle模块
这两个模块的区别在于json更适合跨语言,而pickle仅适用于Python,且pickle能对Python的所有类型进行序列化
通过序列化我们可以实现以下目的:
1、将Python基本数据类型转化为字符串形式
2、将字符串形式转化为Python基本数据类型
import json # 将python基本数据类型转化成字符串形式 dic = {'k1': 'v1'} print(dic,type(dic)) result = json.dumps(dic) print(result,type(result)) # 将python字符串形式转化成基本数据类型 s1 = '{"k1": 123}' dic = json.loads(s1) # 反序列化时,一定要使用 " print(dic,type(dic)) #利用json将Python中的除字符串外的数据类型写入到文件中 #这个过程也是将Python的基本数据类型序列化为字符串形式,然后写入到文件中 li = [11,22,33] json.dump(li,open('db','w')) #利用json将文件中读取出的数据序列化为Python的基本数据类型 li = json.load(open('db','r')) print(type(li),li)
pickle的用法和json的用法类似,这里就不再重复写了
四、字符串格式化
Python的字符创格式化也有两种方式,一个是使用format,另一个是使用%
%用法: 格式符为真实值预留位置,并控制显示的格式。格式符可以包含有一个类型码,用以控制显示的类型,如下: %s 字符串 (采用str()的显示) %r 字符串 (采用repr()的显示) %c 单个字符 %b 二进制整数 %d 十进制整数 %i 十进制整数 %o 八进制整数 %x 十六进制整数 %e 指数 (基底写为e) %E 指数 (基底写为E) %f 浮点数 %F 浮点数,与上相同 %g 指数(e)或浮点数 (根据显示长度) %G 指数(E)或浮点数 (根据显示长度) %% 字符"%" (当格式化时,字符串中出现占位符 %s.. 需要用 %% 输出 %) eg: print("I'm %s. I'm %d year old" % ('xuanouba', 18)) print("I'm %(name)s. I'm %(age)d year old" % {'name':'xuanouba', 'age':18}) 可以用如下的方式,对格式进行进一步的控制: %[(name)][flags][width].[precision]typecode (name)为命名 flags可以有+,-,' '或0。+表示右对齐。-表示左对齐。' '为一个空格,表示在正数的左侧填充一个空格,从而与负数对齐。0表示使用0填充。 width表示显示宽度 precision表示小数点后精度 eg: print("%+10x" % 10) print("%04d" % 5) print("%6.3f" % 2.3)
format用法: 自python2.6开始,新增了一种格式化字符串的函数str.format() 'b' - 二进制. 将数字以2为基数进行输出. 'c' - 字符. 在打印之前将整数转换成对应的Unicode字符串. 'd' - 十进制整数. 将数字以10为基数进行输出. 'o' - 八进制. 将数字以8为基数进行输出. 'x' - 十六进制. 将数字以16为基数进行输出, 9以上的位数用小写字母. 'e' - 幂符号. 用科学计数法打印数字, 用'e'表示幂. 'g' - 一般格式. 将数值以fixed-point格式输出. 当数值特别大的时候, 用幂形式打印. 'n' - 数字. 当值为整数时和'd'相同, 值为浮点数时和'g'相同. 不同的是它会根据区域设置插入数字分隔符. '%' - 百分数. 将数值乘以100然后以fixed-point('f')格式打印, 值后面会有一个百分号. 它通过{}和:来代替%。 通过占位符: print("I'm {},I'm {} year old".format('xuanouba',18)) 通过位置进行映射: print("I'm {0},I‘m {0},I'm {1} year old".format('xuanouba',18)) #下标可重复使用 通过指定key: print("I'm {name},I'm {age} year old".format(name='xuanouba',age=18)) #这几种方式也可以混着用 格式控制: 可以指定所需长度的字符串的对齐方式: < (默认)左对齐 > 右对齐 ^ 中间对齐 = (只用于数字)在小数点后进行补齐 eg: print('{:>8}'.format('189')) #填充与对齐 print('{:.2f}'.format(321.33345) ) #精度 #用,号还能用来做金额的千位分隔符: print('{:,}'.format(1234567890))
五、生成器和迭代器
python专门为for关键字做了迭代器的语法糖。在for循环中,Python将自动调用工厂函数iter()获得迭代器,自动调用next()获取元素,还完成了检查StopIteration异常的工作。
迭代器(iterator)
迭代器用来为类序列对象提供一个类序列的接口。迭代器就是生成一个有next()方法的对象,而不是通过索引来计数。
序列、字典、文件中当使用for x in y的结构时,其实质就是迭代器,迭代器是和实际对象绑定在一起的,所以在使用迭代器时或者上述3者时不能修改可变对象的值。这会产生错误。如:在使用for x in y的结构来遍历字典时删除符合条件的字典内容,这会导致报错。
创建迭代器的方法:iter(object)和iter(func,sentinel)两种。一种使用的是序列,另一种使用类来创建。
迭代器代码示例: def eg(): print(11) yield 1 print(22) yield 2 print(33) yield 3 res = eg() for i in range(3): last_res = res.__next__() print(last_res)
生成器
生成器是特定的函数,允许你返回一个值,然后“暂停”代码的执行,稍后恢复。生成器使用了“延迟计算”,所以在内存上面更加有效。
生成器表达式:(expr for iter_var in iterable if cond_expr)
利用生成器写一个自己的range函数 def myrange(arg): start = 0 while True: if start == arg: break yield start start += 1 res = myrange(10) for i in res: print(i)
详细解释链接:http://www.cnblogs.com/kaituorensheng/p/3826911.html
六、递归:
如果函数包含了对其自身的调用,该函数就是递归的:
eg:
def func(n): n += 1 if n >= 4: return 'end' return func(n) res = func(1) print(res)
def digui(num): if num == 1: return num return num * digui(num-1) res = digui(5) print(res)
这里插入一些关于递归的网方解释,因为我是从网上搜到的这些内容:
(1)递归就是在过程或函数里调用自身;
(2)在使用递归策略时,必须有一个明确的递归结束条件,称为递归出口。
递归算法一般用于解决三类问题:
(1)数据的定义是按递归定义的。(比如Fibonacci函数)
(2)问题解法按递归算法实现。(回溯)
(3)数据的结构形式是按递归定义的。(比如树的遍历,图的搜索)
递归的缺点:递归算法解题的运行效率较低。在递归调用的过程当中系统为每一层的返回点、局部量等开辟了栈来存储。递归次数过多容易造成栈溢出等
七、time,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)
eg:
import datetime,time #根据日期得到时间戳以及struct_time对象 start_time = datetime.date.today() #今天日期 str_start_time = str(start_time) #将日期转化为字符串格式 start_time_struct = time.strptime(str_start_time,"%Y-%m-%d") #将字符串格式的日期转化为struct_time对象 start_time_chuo = time.mktime(start_time_struct) + 28800 #将字符串格式的日期转化为时间戳,时间戳默认是从格林威治时间算起 #根据时间戳得到struct_time对象以及日期 ref_time_struct = time.gmtime(start_time_chuo) #将时间戳转化为struct_time对象 ref_time = time.strftime('%Y-%m-%d',ref_time_struct) #将struct_time对象转化为日期