标签:
1.装饰器
2.列表生成式&迭代器&生成器
3.json&pickle数据序列化
本质上是个函数,功能是装饰其他函数—就是为其他函数添加附加功能
1) 不能修改被装饰函数的源代码;
2) 不能修改被装饰函数的调用方式;
1.3 实现装饰器知识储备:
定义一个函数相当于把函数体赋值给了函数名
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
>>> def func():...... print("这是一个函数")>>> print(func)>>> func()<function func at 0x0000000000D2CD08>这是一个函数#func()是函数调用,而func是函数本身。#要获得函数调用结果,我们可以把结果赋值给变量:>>> a = func()这是一个函数#函数本身赋值给变量>>> a = func<function func at 0x0000000000D2CD08>#结论:函数本身也可以赋值给变量,即:变量可以指向函数。#猜想:是否可以通过变量直接调用函数?>>> a=func>>> a()这是一个函数#说明变量指向了func函数本身,直接调用a()和func()完全相同 |
高阶函数:能接收函数作为参数的函数。
满足下列条件之一就可成函数为高阶函数
某一函数当做参数传入另一个函数中(用处:在不修改被装饰函数源代码的情况下为其添加功能)
|
1
2
3
4
5
6
7
|
>>> def bar(): ......print(‘in the bar‘)>>> def foo(func): ......res=func() ......return res>>> foo(bar)in the bar |
函数的返回值包含n个函数,n>0(用处:不修改函数调用方式)
|
1
2
3
4
5
6
7
8
9
10
11
12
13
|
>>>def bar(): ......time.sleep(3) ......print("in the bar")>>> def test2(func): ......print(func) ......return func>>> print(test2(bar))>>> bar = test2(bar)>>> bar()<function bar at 0x0000000000D6CD08><function bar at 0x0000000000D6CD08><function bar at 0x0000000000D6CD08>in the bar |
map函数会根据提供的函数对指定序列做映射。
map函数的定义:
map(function, sequence[, sequence, ...]) -> list
通过定义可以看到,这个函数的第一个参数是一个函数,剩下的参数是一个或多个序列,返回值是一个集合。
function可以理解为是一个一对一或多对一函数,map的作用是以参数序列中的每一个元素调用function函数,返回包含每次function函数返回值的list。
|
1
2
3
4
5
|
>>> def f(x): ...... return x*x>>> r = map(f,[1,2,3,4,5,6,7,8,9])>>> print(list(r))[1, 4, 9, 16, 25, 36, 49, 64, 81] |
reduce把一个函数作用在一个序列[x1, x2, x3, ...]上,这个函数必须接收两个参数,reduce把结果继续和序列的下一个元素做累积计算。效果就是:
|
1
|
reduce(f, [x1, x2, x3, x4]) = f(f(f(x1, x2), x3), x4) |
|
1
2
3
4
5
|
>>> from functools import reduce>>> def add(x, y): ......return x + y>>> print(reduce(add, [1, 3, 5, 7, 9]))25 |
filter函数会对指定序列执行过滤操作。
filter函数的定义:
filter(function or None, sequence) -> list, tuple, or string
function是一个谓词函数,接受一个参数,返回布尔值True或False。
filter函数会对序列参数sequence中的每个元素调用function函数,最后返回的结果包含调用结果为True的元素。
返回值的类型和参数sequence的类型相同。
|
1
2
3
4
|
>>> def is_odd(n): ...return n % 2 == 1>>> print(list(filter(is_odd, [1, 2, 4, 5, 6, 9, 10, 15])))[1, 5, 9, 15] |
对列表内容进行正向排序,即可以保留原列表,又能得到已经排序好的列表;
|
1
2
3
4
5
|
>>> a = {6:2,8:0,1:4,-5:6,99:11,4:22}>>> print(sorted(a.items())) #按key排序[(-5, 6), (1, 4), (4, 22), (6, 2), (8, 0), (99, 11)]>>> print(sorted(a.items(),key=lambda x:x[1])) #按value排序[(8, 0), (6, 2), (1, 4), (-5, 6), (99, 11), (4, 22)] |
定义:在一个函数体内用def去声明一个新函数
|
1
2
3
4
5
6
7
8
|
>>> def foo(): #定义函数foo() ...m=3 #定义变量m=3; ...def bar(): #在foo内定义函数bar() ...n=4 #定义局部变量n=4 ...print(m+n) #m相当于函数bar()的全局变量 ...bar() #foo()函数内调用函数bar()>>> foo() #调用foo()函数7 |
高阶函数+嵌套函数=>装饰器
不带参数的装饰器:
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
#装饰器import timedef timer(func): def deco(): start_time=time.time() func() #执行形参func() end_time=time.time() print("func runing time is %s"%(end_time-start_time)) return deco #返回函数deco的内存地址def test1(): print("in the test1") time.sleep(1) test1 = timer(test1) #重新赋值test1 此时test1=deco的内存地址test1() #执行test1###########打印输出############in the test1#func runing time is 1.0000572204589844 |
带固定参数的装饰器:
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
#装饰器import timedef timer(func): def deco(name): start_time=time.time() func(name) #执行形参func() end_time=time.time() print("func runing time is %s"%(end_time-start_time)) return deco #返回函数deco的内存地址@timer #test1 = timer(test1) test1=decodef test1(name): print("in the test1 name %s"%name) time.sleep(1) test1("cc") #执行test1###########打印输出############in the test1 name cc#func runing time is 1.0000572204589844 |
带返回值的装饰器:
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
#装饰器import timedef timer(func): def deco(*args,**kwargs): start_time=time.time() res = func(*args,**kwargs) #执行形参func() end_time=time.time() print("func runing time is %s"%(end_time-start_time)) return res return deco #返回函数deco的内存地址@timer #test1 = timer(test1) test1=decodef test1(name): print("in the test1 name %s"%name) time.sleep(1) return "return form test1" print(test1("cc")) #执行test1###########打印输出############in the test1 name cc#func runing time is 1.0000572204589844#return form test1 |
通过以上我们会发现一个问题,选用的装饰器只能选择统一带形参或者统一不带形参;那么问题来了,我想要用一个装饰器,带形参的能调用,不带形参的也能调用,可不可以呢?
带不固定参数的装饰器:
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
|
# 装饰器import timedef timer(func): def deco(*args, **kwargs): start_time = time.time() func(*args, **kwargs) # 执行形参func() end_time = time.time() print("func runing time is %s" % (end_time - start_time)) return deco # 返回函数deco的内存地址@timer # test1 = timer(test1) test1=decodef test1(name): print("in the test1 name %s" % name) time.sleep(1)@timerdef test2(): print("in the test2 no name") time.sleep(1)test1("cc") # 执行test1test2() # 执行test2###########打印输出###########in the test1 name ccfunc runing time is 1.0010571479797363in the test2 no namefunc runing time is 1.0000572204589844 |
终极版装饰器:
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
|
import timeuser,passwd = ‘cc‘,‘123123‘def auth(auth_type): print(‘auth func:‘,auth_type) def outer_wrapper(func): def wrapper(*args,**kwargs): print("wrapper func args:",*args,**kwargs) if auth_type == ‘local‘: username = input("Username:").strip() password = input("Password:").strip() if user == username and passwd == password: print("User has passed authentication!") res = func(*args,**kwargs) print("---after authentication") return res else: exit("Invalid username or password!") elif auth_type == "ldap": print("搞毛线ldap,不会。。。") return wrapper return outer_wrapperdef index(): print("welcome to index page")@auth(auth_type=‘local‘)#home = wrapper()def home(): print("welcome to home page") return "from home"@auth(auth_type="ldap")def bbs(): print("welcome to bbs page")index()print(home()) #wrapper()bbs() |
列表生成式,是Python内置的一种极其强大的生成list的表达式。
如果要生成一个list [1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9] 可以用 range(1 , 10):
|
1
2
|
#print(list(range(1,10)))[1, 2, 3, 4, 5, 6, 7, 8, 9] |
如果要生成[1x1, 2x2, 3x3, ..., 10x10]怎么做?
|
1
2
3
4
5
6
|
l = []for i in range(1,10): l.append(i*i)print(l)####打印输出#####[1, 4, 9, 16, 25, 36, 49, 64, 81] |
而列表生成式则可以用一行语句代替循环生成上面的list:
|
1
2
|
>>> print([x*x for x in range(1,10)])[1, 4, 9, 16, 25, 36, 49, 64, 81] |
for循环后面还可以加上if判断,这样我们就可以筛选出仅偶数的平方:
|
1
2
|
>>> print([x*x for x in range(1,10) if x %2 ==0])[4, 16, 36, 64] |
通过列表生成式,我们可以直接创建一个列表。但是,受到内存限制,列表容量肯定是有限的。而且,创建一个包含100万个元素的列表,不仅占用很大的存储空间,如果我们仅仅需要访问前面几个元素,那后面绝大多数元素占用的空间都白白浪费了。
所以,如果列表元素可以按照某种算法推算出来,那我们是否可以在循环的过程中不断推算出后续的元素呢?这样就不必创建完整的list,从而节省大量的空间。在Python中,这种一边循环一边计算的机制,称为生成器:generator。
要创建一个generator,有很多种方法。第一种方法很简单,只要把一个列表生成式的[]改成(),就创建了一个generator:
|
1
2
3
4
5
6
|
>>> L = [x * x for x in range(10)]>>> print(L)[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]>>> g = (x * x for x in range(10))>>> print(g)<generator object <genexpr> at 0x1022ef630> |
创建L和g的区别仅在于最外层的[]和(),L是一个list,而g是一个generator。
我们可以直接打印出list的每一个元素;而generator里的每一个元素我们可以通过next()函数获取:
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
|
>>> g = (x * x for x in range(10))>>> print(g)>>> print(next(g))>>> print(next(g))>>> print(next(g))>>> print(next(g))>>> print(next(g))>>> print(next(g))>>> print(next(g))>>> print(next(g))>>> print(next(g))>>> print(next(g))>>> print(next(g))0149162536496481Traceback (most recent call last): File "XXX", line 32, in <module> print(next(g))StopIteration |
上面我们可以看到,每次调用next(g),就计算出g的下一个元素的值,直到计算到最后一个元素,没有更多的元素时,抛出StopIteration的错误。
当然,我们也可以通过for循环去调取元素值:
|
1
2
3
4
5
6
7
8
9
10
11
12
13
|
>>> g = (x * x for x in range(10))>>> for i in g:>>> print(i)0149162536496481 |
generator非常强大。如果推算的算法比较复杂,用类似列表生成式的for循环无法实现的时候,还可以用函数来实现。
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
#斐波拉契数列def fib(max): n, a, b = 0, 0, 1 while n < max: print(b) a, b = b, a + b n += 1 return ‘done‘ fib(5)###########打印输出############ 1# 1# 2# 3# 5 |
仔细观察,可以看出,fib函数实际上是定义了斐波拉契数列的推算规则,可以从第一个元素开始,推算出后续任意的元素,这种逻辑其实非常类似generator。
也就是说,上面的函数和generator仅一步之遥。要把fib函数变成generator,只需要把print(b)改为yield b就可以了:
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
#斐波拉契数列def fib(max): n, a, b = 0, 0, 1 while n < max: yield(b) a, b = b, a + b n += 1 return ‘done‘ f = fib(5)print(f)for i in f: print(i)###########打印输出############<generator object fib at 0x000000000110A468>#1#1#2#3#5 |
这就是定义generator的另一种方法。如果一个函数定义中包含yield关键字,那么这个函数就不再是一个普通函数,而是一个generator。
generator和函数的执行流程不一样。函数是顺序执行,遇到return语句或者最后一行函数语句就返回。而变成generator的函数,在每次调用next()的时候执行,遇到yield语句返回,再次执行时从上次返回的yield语句处继续执行。
上面我们会发现:用for循环调用generator时,发现拿不到generator的return语句的返回值。如果想要拿到返回值,必须捕获StopIteration错误,返回值包含在StopIteration的value中:
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
def fib(max): n, a, b = 0, 0, 1 while n < max: yield b a, b = b, a + b n = n + 1 return ‘done‘g = fib(6)while True: try: x = next(g) print(‘g:‘, x) except StopIteration as e: print(‘Generator return value:‘, e.value) break####打印输出##### g: 1# g: 1# g: 2# g: 3# g: 5# g: 8# Generator return value: done |
生成器的特点:
1)生成器只有在调用时才会生成相应的数据;
2)只记录当前位置;
3)只有一个__next__()方法;
还可通过yield实现在单线程的情况下实现并发运算的效果:
import timedef 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(10): time.sleep(1) print("做了2个包子!") c.send(i) c2.send(i)producer("cc") |
标签:
原文地址:http://www.cnblogs.com/wangsen-123/p/5783344.html