本节课程内容概览:
1.装饰器
2.列表生成式&迭代器&生成器
3.json&pickle数据序列化
1. 装饰器
1.1 定义:
本质上是个函数,功能是装饰其他函数—就是为其他函数添加附加功能
1.2 装饰器原则:
1) 不能修改被装饰函数的源代码;
2) 不能修改被装饰函数的调用方式;
1.3 实现装饰器知识储备:
1.3.1 函数即“变量”
定义一个函数相当于把函数体赋值给了函数名
变量可以指向函数
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.3.2 高阶函数
高阶函数:能接收函数作为参数的函数。
满足下列条件之一就可成函数为高阶函数
- 某一函数当做参数传入另一个函数中(用处:在不修改被装饰函数源代码的情况下为其添加功能)
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 )]
|
1.3.3 嵌套函数
定义:在一个函数体内用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.3.4 装饰器
高阶函数+嵌套函数=>装饰器
不带参数的装饰器:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
#装饰器
import time
def 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 time
def 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=deco
def 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 time
def 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=deco
def 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 time
def 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=deco
def test1(name):
print ( "in the test1 name %s" % name)
time.sleep( 1 )
@timer
def test2():
print ( "in the test2 no name" )
time.sleep( 1 )
test1( "cc" ) # 执行test1
test2() # 执行test2
###########打印输出###########
in the test1 name cc
func runing time is 1.0010571479797363
in the test2 no name
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
22
23
24
25
26
27
28
29
30
31
32
33
|
import time
user,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_wrapper
def 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()
|
2. 迭代器&生成器
2.1 列表生成式
列表生成式,是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 ]
|
2.2 生成器
通过列表生成式,我们可以直接创建一个列表。但是,受到内存限制,列表容量肯定是有限的。而且,创建一个包含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))
0
1
4
9
16
25
36
49
64
81
Traceback (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)
0
1
4
9
16
25
36
49
64
81
|
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 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 ( 10 ):
time.sleep( 1 )
print ( "做了2个包子!" )
c.send(i)
c2.send(i)
producer( "cc" )
|
2.3 迭代器
3.json&pickle数据序列化
时间: 2024-10-12 12:13:11