码迷,mamicode.com
首页 > 编程语言 > 详细

python-day5-装饰器补充、模块、字符串格式化和序列化

时间:2016-06-07 19:07:10      阅读:320      评论:0      收藏:0      [点我收藏+]

标签:

装饰器补充之双层装饰器

技术分享
 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()
View Code

注意:双层装饰器的执行过程

  • 解释器是从下往上依次加载装饰器,以上面代码为例,解释器先将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
View Code

    

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
View Code

如果函数包含了对其自身的调用,该函数就是递归的。

这里插入一些关于递归的网方解释,因为我是从网上搜到的这些内容:
(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
View Code

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>
View Code

注意:将字符串反序列化成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>
View Code

 

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模块级别

LevelWhen 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-装饰器补充、模块、字符串格式化和序列化

标签:

原文地址:http://www.cnblogs.com/gouyc/p/5567836.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!