装饰器本质是函数,装饰其他函数,就是为其他函数添加附加功能。
原则:1.不能修改被装饰的函数的源代码
2.不能修改被装饰的函数的调用方式
实现装饰器 知识储备
1.函数即“变量”
2.高阶函数
a.把一个函数当作实参传给另外一个函数(在不修改被装饰函数源代码的情况下 为其添加功能)
b.返回值中包含函数名(不修改函数的调用方式)
3.嵌套函数
高阶函数+嵌套函数 = 装饰器
高阶函数#变量可以指向函数,函数的参数能接收变量,那么一个函数就可以接收另一个函数作为参数,这种函数就称之为高阶函数。 嵌套函数:在一个函数体内创建另外一个函数,这种函数就叫内嵌函数(基于python支持静态嵌套域)
知识回顾
高阶函数
def bar(): print ("in the bar") def foo(func): res=func() return res foo(bar)
#!/usr/bin/env python #-*- coding:utf-8 -*- # Author:DCCimport import time def bar(): time.sleep(2) print("in the bar") def test1(func): start_time=time.time() func() stop_time=time.time() print("run time is %s" %(stop_time-start_time)) test1(bar)
嵌套函数
y = 10 # def test(): # y+=1 # print y def test(): # global y y = 2 print(y) test() print(y) def dad(): m = 1 def son(): n = 2 print('--->', m + n) print('-->',m) son() dad()
注:函数是存在内存中的,只有退出程序后函数才从内存中删除。如果想删除内存中的函数,用del
匿名函数
lambda x:x*3 calc = lambda x:x*3 print(calc(3))
运行结果:
9
装饰器
(1)单独以f1为例:
def w1(func): def inner(): # 验证1 # 验证2 # 验证3 return func() return inner @w1 def f1(): print 'f1'
当写完这段代码后(函数未被执行、未被执行、未被执行),python解释器就会从上到下解释代码,步骤如下:
def w1(func): ==>将w1函数加载到内存
@w1
没错,从表面上看解释器仅仅会解释这两句代码,因为函数在没有被调用之前其内部代码不会被执行。
从表面上看解释器着实会执行这两句,但是 @w1 这一句代码里却有大文章,@函数名 是python的一种语法糖。
如上例@w1内部会执行一下操作:
执行w1函数,并将 @w1 下面的 函数 作为w1函数的参数,即:@w1 等价于 w1(f1)
所以,内部就会去执行:
def inner:
#验证
return f1() # func是参数,此时 func 等于 f1
return inner # 返回的 inner,inner代表的是函数,非执行函数
其实就是将原来的 f1 函数塞进另外一个函数中将执行完的 w1 函数返回值赋值给@w1下面的函数的函数名
w1函数的返回值是:
def inner:
#验证
return 原来f1() # 此处的 f1 表示原来的f1函数
然后,将此返回值再重新赋值给 f1,即:
新f1 = def inner:
#验证
return 原来f1()
所以,以后业务部门想要执行 f1 函数时,就会执行 新f1 函数,在 新f1 函数内部先执行验证,再执行原来的f1函数,然后将 原来f1 函数的返回值 返回给了业务调用者。
如此一来, 即执行了验证的功能,又执行了原来f1函数的内容,并将原f1函数返回值 返回给业务调用着
(2)问答时间
问题:一个函数可以被多个装饰器装饰吗?
def w1(func): def inner(*args,**kwargs): # 验证1 # 验证2 # 验证3 return func(*args,**kwargs) return inner def w2(func): def inner(*args,**kwargs): # 验证1 # 验证2 # 验证3 return func(*args,**kwargs) return inner @w1 @w2 def f1(arg1,arg2,arg3): print 'f1'
2、生成器
列表生成式(中括号)
优点:使代码更简洁,也可以执行函数
list=[ i*2 for i in range(10)] print(list)
运行结果
[0, 2, 4, 6, 8, 10, 12, 14, 16, 18]
注:range默认是从0开始的。
通过列表生成式,我们可以直接创建一个列表。但是,受到内存限制,列表容量肯定是有限的。而且,创建一个包含100万个元素的列表,不仅占用很大的存储空间,如果我们仅仅需要访问前面几个元素,那后面绝大多数元素占用的空间都白白浪费了。
所以,如果列表元素可以按照某种算法推算出来,那我们是否可以在循环的过程中不断推算出后续的元素呢?这样就不必创建完整的list,从而节省大量的空间。在Python中,这种一边循环一边计算的机制,称为生成器:generator。
要创建一个generator,有很多种方法。第一种方法很简单,只要把一个列表生成式的[]
改成()
,就创建了一个generator:
l是一个list[],g是一个generator()
generator保存的是算法,每次调用next(g)
,就计算出g
的下一个元素的值,直到计算到最后一个元素,没有更多的元素时,抛出StopIteration
的错误。
#!/usr/bin/env python #-*- coding:utf-8 -*- # Author:DCC l = [x * x for x in range(5)] print(l) g = (x * x for x in range(5)) print(g) print(next(g)) print(next(g)) print(next(g)) print(next(g)) print(next(g)) print(next(g)) #运行结果 [0, 1, 4, 9, 16] <generator object <genexpr> at 0x00000000006969E8> 1 9 Traceback (most recent call last): File "<stdin>", line 1, in <module> StopIteration
小结:生成器与列表的区别
生成器:调用的时候才会生成
列表:先执行出所有的值
用函数制作生成器
斐波拉契数列:
def fib(max): n, a, b = 0, 0, 1 while n < max: print(b) a, b = b, a + b n = n + 1 return 'done' fib(10) #运行结果 1 3 8 21 55
a, b
=
b, a
+
b
相当于
t
=
(b, a
+
b)
# t是一个tuple
a
=
t[
0
]
b
=
t[
1
]
******yield 将print(b)改为yield b,fib函数变成generator
def fib(max): n,a,b = 0,0,1 while n < max: #print(b) yield b a,b = b,a+b n += 1 return 'done' print(fib(5)) print(fib(5).__next__()) print(fib(5).__next__()) #运行结果 <generator object fib at 0x000001CDB2D511A8> 1
通过yield实现在单线程的情况下实现并发运算的效果, send的使用
import time def consumer(name): print("%s 准备吃包子啦!" %name) while True: baozi = yield print("包子[%s]来了,被[%s]吃了!" %(baozi,name)) def producer(name): c = consumer('A') c2 = consumer('B') c.__next__() c2.__next__() print("老子开始准备做包子啦!") for i in range(5): time.sleep(1) print("做了2个包子!") c.send(i) c2.send(i) producer("dcc") #运行结果 A 准备吃包子啦! B 准备吃包子啦! 老子开始准备做包子啦! 做了2个包子! 包子[0]来了,被[A]吃了! 包子[0]来了,被[B]吃了! 做了2个包子! 包子[1]来了,被[A]吃了! 包子[1]来了,被[B]吃了! 做了2个包子! 包子[2]来了,被[A]吃了! 包子[2]来了,被[B]吃了! 做了2个包子! 包子[3]来了,被[A]吃了! 包子[3]来了,被[B]吃了! 做了2个包子! 包子[4]来了,被[A]吃了! 包子[4]来了,被[B]吃了!
注:
__next__ 只会调用yield
send不仅会调用yield,野会给yield传个值
3、迭代器
Iterable:可迭代的
Iterator:迭代器
凡是可作用于for
循环的对象都是Iterable
类型;
凡是可作用于next()
函数的对象都是Iterator
类型,它们表示一个惰性计算的序列;
简而言之:
1.可用于for循环的
2.有next方法的就可以成为迭代器
集合数据类型如list
、dict
、str
等是Iterable
但不是Iterator
,不过可以通过iter()
函数获得一个Iterator
对象。
这些可以直接作用于for
循环的对象统称为可迭代对象:Iterable
。
可以使用isinstance()
判断一个对象是否是Iterable
对象
可以被next()函数调用并不断返回下一个值的对象称为迭代器:Iterator。
>>> from collections import Iterator >>> isinstance((x for x in range(10)), Iterator) True >>> isinstance([], Iterator) False >>> isinstance({}, Iterator) False >>> isinstance('abc', Iterator) False
生成器都是Iterator
对象,但list
、dict
、str
虽然是Iterable
,却不是Iterator
。
把list
、dict
、str
等Iterable
变成Iterator
可以使用iter()
函数:
>>> isinstance(iter([]), Iterator) True >>> isinstance(iter('abc'), Iterator) True
实例
#!/usr/bin/env python #-*- coding:utf-8 -*- # Author:DCC import time def timer(func): def deco(*args,**kwargs): # def warpper(*args,**kwargs): start_time = time.time() func(*args,**kwargs) stop_time = time.time() print("the func run time is %s" % (stop_time-start_time) ) return deco @timer # test1 = timer(test1) def test1(): time.sleep(3) print("in the test1") @timer # test2 = timer(test2) =deco def test2(name,age): print(name,age) print("in the test2") test1() test2("dcc","2;5")
4、json的简单实用
json官方说明参见:http://json.org/
Python操作json的标准api库参考:http://docs.python.org/library/json.html
重要函数
编码:把一个Python对象编码转换成Json字符串 json.dumps()
解码:把Json格式字符串解码转换成Python对象 json.loads()
>>> import json >>> info = { "name":"test", "age":"25", "sex":"man", "type":{"name1":"test1","parameter":["1","2"]} } >>> print(type(info)) <class 'dict'> >>> j = json.dumps(info) >>> print(j) {"sex": "man", "type": {"name1": "test1", "parameter": ["1", "2"]}, "age": "25", "name": "test"} >>> d = json.loads(j) >>> print(d) {'age': '25', 'type': {'name1': 'test1', 'parameter': ['1', '2']}, 'sex': 'man', 'name': 'test'} >>> print(type(d)) <class 'dict'>
sort_keys(对dict对象进行排序,我们知道默认dict是无序存放的)
#!/usr/bin/env python #-*- coding:utf-8 -*- # Author:DCC import json data1 = {'b':789,'c':456,'a':123} data2 = {'a':123,'b':789,'c':456} d1 = json.dumps(data1,sort_keys=True) d2 = json.dumps(data2) d3 = json.dumps(data2,sort_keys=True) print(d1) print(d2) print(d3) #运行结果 {"a": 123, "b": 789, "c": 456} {"b": 789, "a": 123, "c": 456} {"a": 123, "b": 789, "c": 456}
indent 解码缩进
#!/usr/bin/env python #-*- coding:utf-8 -*- # Author:DCC data1 = {'b':789,'c':456,'a':123} d1 = json.dumps(data1,sort_keys=True,indent=4) d2 = json.dumps(data1,sort_keys=True) print(d1) print(d2) #运行结果 { "a": 123, "b": 789, "c": 456 } {"a": 123, "b": 789, "c": 456}
用于序列化的两个模块
json,用于字符串 和 python数据类型间进行转换
pickle,用于python特有的类型 和 python的数据类型间进行转换
Json模块提供了四个功能:dumps、dump、loads、load
pickle模块提供了四个功能:dumps、dump、loads、load