python-day5-装饰器补充模块字符串格式化和序列化
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了python-day5-装饰器补充模块字符串格式化和序列化相关的知识,希望对你有一定的参考价值。
装饰器补充之双层装饰器
1 user_info = {} 2 3 4 def check_login(func): 5 def inner(*args, **kwargs): 6 if user_info.get(‘is_login‘, None): 7 ret = func(*args, **kwargs) 8 return ret 9 else: 10 print(‘请先登录...‘) 11 return inner 12 13 14 def check_user_type(func): 15 def inner(*args, **kwargs): 16 if user_info.get(‘user_type‘, None) == 1: 17 ret = func(*args, **kwargs) 18 return ret 19 else: 20 print(‘无权限查看...‘) 21 return inner 22 23 24 def login(): 25 user = input(‘请输入用户名: ‘) 26 if user == ‘admin‘: 27 user_info[‘is_login‘] = True 28 user_info[‘user_type‘] = 1 29 else: 30 user_info[‘is_login‘] = True 31 user_info[‘user_type‘] = 2 32 33 @check_login 34 @check_user_type 35 def index(): 36 """ 37 管理员的功能 38 :return: 39 """ 40 print(‘index‘) 41 42 @check_login 43 def home(): 44 """ 45 普通用户的功能 46 :return: 47 """ 48 print(‘home‘) 49 50 51 def main(): 52 while True: 53 int = input(‘1. 登录 2.查看信息 3.超级管理员\\n>>>‘) 54 if int == ‘1‘: 55 login() 56 elif int == ‘2‘: 57 home() 58 elif int == ‘3‘: 59 index() 60 61 62 main()
注意:双层装饰器的执行过程
- 解释器是从下往上依次加载装饰器,以上面代码为例,解释器先将check_user_type和原函数index()加载到内存,然后将check_user_type的inner函数返回给check_login装饰器。
- 执行时,先执行最外层的check_login装饰器,然后执行check_user_type装饰器。
- 执行时,如果第一个装饰器if条件不成立,那么第二个装饰器不会执行。
- 执行时,如果第一个装饰器if条件成立,那么继续执行第二个装饰器。
字符串格式化
目前python支持百分号和format来完成字符串格式化的操作,百分号是2.0版本的。format方式是3.0版本的。
format支持的格式比百分号方式多。
1、百分号方式
1 str = "my name is %s, age is %d" 2 print(str%(‘john‘, 23))
%[(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中百分号格式化是不存在自动将整数转换成二进制表示的方式
常用格式化
1 tpl = "i am %s" % "john" 2 3 tpl = "i am %s age %d" % ("john", 18) 4 5 tpl = "i am %(name)s age %(age)d" % {"name": "john", "age": 18} 6 7 tpl = "percent %.2f" % 99.97623 8 9 tpl = "i am %(pp).2f" % {"pp": 123.425556, } 10 11 tpl = "i am %.2f %%" %123.425556
format方式
1 str = "my name is {0}, age is {1}" 2 print(str.format(‘john‘,25))
[[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位)
常用格式化:
1 tpl = "i am {}, age {}, {}".format("john", 25, ‘john‘) 2 3 tpl = "i am {}, age {}, {}".format(*["john", 25, ‘john‘]) 4 5 tpl = "i am {0}, age {1}, really {0}".format("john", 25) 6 7 tpl = "i am {0}, age {1}, really {0}".format(*["john", 25]) 8 9 tpl = "i am {name}, age {age}, really {name}".format(name="john", age=25) 10 11 tpl = "i am {name}, age {age}, really {name}".format(**{"name": "john", "age": 25}) 12 13 tpl = "i am {0[0]}, age {0[1]}, really {0[2]}".format([‘john‘, 25, ‘john‘], [11, 22, 33]) 14 15 tpl = "i am {:s}, age {:d}, money {:f}".format("john", 25, 88888.1) 16 17 tpl = "i am {:s}, age {:d}".format(*["john", 25]) 18 19 tpl = "i am {name:s}, age {age:d}".format(name="john", age=25) 20 21 tpl = "i am {name:s}, age {age:d}".format(**{"name": "john", "age": 25}) 22 23 tpl = "numbers: {:b},{:o},{:d},{:x},{:X}, {:%}".format(15, 15, 15, 15, 15, 15.87623, 2) 24 25 tpl = "numbers: {:b},{:o},{:d},{:x},{:X}, {:%}".format(15, 15, 15, 15, 15, 15.87623, 2) 26 27 tpl = "numbers: {0:b},{0:o},{0:d},{0:x},{0:X}, {0:%}".format(15) 28 29 tpl = "numbers: {num:b},{num:o},{num:d},{num:x},{num:X}, {num:%}".format(num=15)
更多格式化操作:https://docs.python.org/3/library/string.html
生成器和迭代器
1、生成器Generators
生成器是一个有生成数据能力的对象。函数中如果用到了yield语法,那么这个函数就是一个生成器
特点:
- 生成器是一个函数,而且函数的参数都会保留,生成器返回的数据是可迭代的对象。
- 迭代到下一次的调用时,所使用的参数都是第一次所保留下的,即是说,在整个所有函数调用的参数都是第一次所调用时保留的,而不是新创建的
yield 生成器的运行机制:
-
当你问生成器要一个数时,生成器会执行,直至出现 yield 语句,生成器把 yield 的参数给你,之后生成器就不会往下继续运行。 当你问他要下一个数时,他会从上次的状态。开始运行,直至出现yield语句,把参数给你,之后停下。如此反复,直至退出函数。
yield的使用:
- 当你定义一个函数,使用了yield关键字时,这个函数就是一个生成器,它的执行会和其他普通的函数有很多不同,函数返回的是一个对象,而不是你平常 所用return语句那样,能得到结果值。如果想取得值,那得调用next()函数或者迭代器。
1 def xf(): 2 yield 1 3 yield 2 4 yield 3 5 6 ret = xf() 7 print(ret.__next__()) 8 print(ret.__next__()) 9 print(ret.__next__()) 10 print(ret.__next__()) 11 12 结果: 13 14 1 15 2 16 3 17 File "/Users/TheOne/PycharmProjects/s13/day5/day5-课上/module.py", line 15, in <module> 18 print(ret.__next__()) 19 StopIteration
2、迭代器Iterators
迭代器是访问集合元素的一种方式。迭代器对象从集合的第一个元素开始访问,直到所有的元素被访问完结束。迭代器只能往前不会后退,不过这也没什么,因为人们很少在迭代途中往后退。
优点:
- 对于原生支持随机访问的数据结构(如tuple、list),迭代器和经典for循环的索引访问相比并无优势,反而丢失了索引值(可以使用内建函数enumerate()找回这个索引值)。但对于无法随机访问的数据结构(比如set)而言,迭代器是唯一的访问元素的方式。
- 迭代器的一大优点是不要求事先准备好整个迭代过程中所有的元素。迭代器仅仅在迭代到某个元素时才计算该元素,而在这之前或之后,元素可以不存在或者被销毁。这个特点使得它特别适合用于遍历一些巨大的或是无限的集合,比如几个G的文件,或是斐波那契数列等等
- 迭代器更大的功劳是提供了一个统一的访问集合的接口,只要定义了__iter__()方法对象,就可以使用迭代器访问
说明:for循环内部就是使用了next方法实现了遍历
递归
1 def fo(arg): 2 arg += 1 3 if arg >= 5: 4 print(arg) 5 else: 6 return fo(arg) 7 fo(1) 8 9 结果: 10 5
如果函数包含了对其自身的调用,该函数就是递归的。
这里插入一些关于递归的网方解释,因为我是从网上搜到的这些内容:
(1)递归就是在过程或函数里调用自身;
(2)在使用递归策略时,必须有一个明确的递归结束条件,称为递归出口。
递归算法一般用于解决三类问题:
(1)数据的定义是按递归定义的。(比如Fibonacci函数)
(2)问题解法按递归算法实现。(回溯)
(3)数据的结构形式是按递归定义的。(比如树的遍历,图的搜索)
递归的缺点:递归算法解题的运行效率较低。在递归调用的过程当中系统为每一层的返回点、局部量等开辟了栈来存储。递归次数过多容易造成栈溢出等。
参考:http://www.cnblogs.com/balian/archive/2011/02/11/1951054.html
模块
为什么要有模块?
现在,我们写一些小项目时,都喜欢把所有的函数都放在一个文件里面(.py)。那么如果以后写大型项目,涉及到的函数可能有几百几千个,那个时候我们如果要更改某个函数的函数功能。缺点如下:
- 查找不便
- 单个文件代码太多,不宜更改。杂乱无章。
为了解决上面的难题,就用到了模块,模块和普通的程序一样,只不过模块文件中存放的全部都是业务处理的唯一功能,比如。用户操作的函数写在一个文件中,后台管理类的函数放在一个文件中。在主程序需要用到的时候,直接导入模块,执行对应的函数功能即可。优点如下:
- 易维护,方便代码管理
- 查找方便。
导入模块的依据
模块的导入都是针对当前执行程序的目录而言的,python会先到当前程序执行的目录去查找模块,如果找不到,会接着到python定义的几个目录中去查找。如果还找不到,那么就会报错。
1 import sys 2 for i in sys.path: 3 print(i) 4 结果: 5 /Users/TheOne/PycharmProjects/s13/day5/day5-课上 6 /Users/TheOne/PycharmProjects/s13 7 /Library/Frameworks/Python.framework/Versions/3.5/lib/python35.zip 8 /Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5 9 /Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/plat-darwin 10 /Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/lib-dynload 11 /Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/site-packages
python将所有的查找路径都放到了sys.path中以列表的方式保存,如果我们想到除以上路径外的其它地方加载模块,那么将模块的目录append到sys.path中即可。
模块名称的重要性
为了避免自定义模块和系统或第三方模块的name冲突,在自定义模块的时候,要尽量避开系统模块名 。或者为自定义模块赋予别名。
模块的导入方法
1、如果在同一目录下:
import 模块名
2、在当前目录下的其它目录
from 目录名 import 模块名
3、导入模块并命名别名
from 目录名 import 模块名 as 别名
序列化
json(适合所有程序语言,可以跨语言平台,用来在不同语言平台中交换数据。json只支持基本数据类型,即字符串,字典,列表,元素,数字等)
功能:
- 将python的数据类型系列化成字符串(因为字符串是各语言平台都支持的数据类型,因此。使用字符串来在各平台中传递数据)
- 将字符串反序列化成python的数据类型
- 将python数据序列化到文件中
- 从文件中将数据反序列化到python
1 将python数据类型序列化成字符串 2 3 import json 4 dic = {‘name‘:‘john‘,‘age‘:25} 5 print(dic, type(dic)) 6 ret = json.dumps(dic) 7 print(ret, type(ret)) 8 结果: 9 {‘age‘: 25, ‘name‘: ‘john‘} <class ‘dict‘> 10 {"age": 25, "name": "john"} <class ‘str‘> 11 12 将字符串反序列化成python数据类型 13 import json 14 dic = ‘{"name":"john","age":25}‘ 15 print(dic, type(dic)) 16 ret = json.loads(dic) 17 print(ret, type(ret)) 18 结果: 19 {"name":"john","age":25} <class ‘str‘> 20 {‘age‘: 25, ‘name‘: ‘john‘} <class ‘dict‘>
注意:将字符串反序列化成python数据类型,一定要用单引号,否则报错。因为,在其他语言平台,单引号的叫字符,双引号的叫字符串
1 将python数据序列化到文件中 2 import json 3 dic = {"name":"john","age":25} 4 json.dump(dic, open(‘db‘, ‘w‘)) 5 6 从文件中反序列化到python 7 ret = json.load(open(‘db‘, ‘r‘)) 8 print(ret, type(ret)) 9 结果: 10 {‘name‘: ‘john‘, ‘age‘: 25} <class ‘dict‘>
pickle(支持python中的任意数据类型,基本数据类型和对象等。只能在python中使用,不支持跨语言平台使用)
功能和json一样,只不过pickle在序列化时,将python数据转换成了pickle的特定格式。
功能:
- 将python数据序列化到文件中
- 从文件中将数据反序列化到python
- 支持字节的方式,即打开文件时,使用wb和rb模式
- 将python数据类型序列化成pickle特定格式
- 将pickle格式序列化成python数据类型
time&datetime模块
#_*_coding:utf-8_*_ 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)
loggin模块
很多程序都有记录日志的需求,并且日志中包含的信息即有正常的程序访问日志,还可能有错误、警告等信息输出,python的logging模块提供了标准的日志接口,你可以通过它存储各种格式的日志,logging的日志可以分为 debug()
, info()
, warning()
, error()
and critical() 5个级别,
下面我们看一下怎么用。
loggin模块级别
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. |
如果想把日志写到文件里,也很简单
1 import logging 2 3 logging.basicConfig(filename=‘example.log‘,level=logging.INFO) 4 logging.debug(‘This message should go to the log file‘) 5 logging.info(‘So should this‘) 6 logging.warning(‘And this, too‘)
|
其中下面这句中的level=loggin.INFO意思是,把日志纪录级别设置为INFO,也就是说,只有比日志是INFO或比INFO级别更高的日志才会被纪录到文件里,在这个例子, 第一条日志是不会被纪录的,如果希望纪录debug的日志,那把日志级别改成DEBUG就行了。
1 logging.basicConfig(filename=‘example.log‘,level=logging.INFO)
感觉上面的日志格式忘记加上时间啦,日志不知道时间怎么行呢,下面就来加上!
1 import logging 2 logging.basicConfig(format=‘%(asctime)s %(message)s‘, datefmt=‘%m/%d/%Y %I:%M:%S %p‘) 3 logging.warning(‘is when this event was logged.‘) 4 5 #输出 6 12/12/2010 11:46:36 AM is when this event was logged.
如果想同时把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.
1 import logging 2 3 #create logger 4 logger = logging.getLogger(‘TEST-LOG‘) 5 logger.setLevel(logging.DEBUG) 6 7 8 # create console handler and set level to debug 9 ch = logging.StreamHandler() 10 ch.setLevel(logging.DEBUG) 11 12 # create file handler and set level to warning 13 fh = logging.FileHandler("access.log") 14 fh.setLevel(logging.WARNING) 15 # create formatter 16 formatter = logging.Formatter(‘%(asctime)s - %(name)s - %(levelname)s - %(message)s‘) 17 18 # add formatter to ch and fh 19 ch.setFormatter(formatter) 20 fh.setFormatter(formatter) 21 22 # add ch and fh to logger 23 logger.addHandler(ch) 24 logger.addHandler(fh) 25 26 # ‘application‘ code 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‘)
以上是关于python-day5-装饰器补充模块字符串格式化和序列化的主要内容,如果未能解决你的问题,请参考以下文章