python中的yield:
在之前发布的《python之列表解析与生成器》中我们有提到过,生成器所实现的是跟列表解析近似的效果,但是我们不能对生成器做一些属于列表解析的操作。
因为生成器本身就不是一个列表,它只是模拟了一个类似列表的行为,因此,施加在列表中的很多操作,对生成器而言是无效的。
由于生成器表达式并不会直接创建出序列形式的列表,因此不能对其进行索引、切片,不能执行任何常规的列表操作。比如:弹出元素(pop())、添加元素(append())等等。但是我们可以通过list函数将生成器转换成列表。
1
2
|
In [
1
]:
list
((i
*
*
2
for
i
in
range
(
1
,
11
)))
Out[
1
]: [
1
,
4
,
9
,
16
,
25
,
36
,
49
,
64
,
81
,
100
]
|
很多情况下我们需要生成更为复杂的结果,又不想基于某个列表来实现,但是简单的使用一个生成器表达式很难实现此种行为。此时我们可以通过一个自定义函数来完全实现类似的效果。
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
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
|
In [
2
]:
def
genNum(x):
...: y
=
0
...:
while
y <
=
x:
...:
yield
y
...: y
+
=
1
...:
In [
3
]: g1
=
genNum(
10
)
In [
4
]:
type
(g1)
Out[
4
]: generator
In [
5
]: g1.
next
()
Out[
5
]:
0
In [
6
]: g1.
next
()
Out[
6
]:
1
In [
7
]: g1.
next
()
Out[
7
]:
2
In [
8
]: g1.
next
()
Out[
8
]:
3
In [
9
]: g1.
next
()
Out[
9
]:
4
In [
10
]: g1.
next
()
Out[
10
]:
5
In [
11
]: g1.
next
()
Out[
11
]:
6
In [
12
]: g1.
next
()
Out[
12
]:
7
In [
13
]: g1.
next
()
Out[
13
]:
8
In [
14
]: g1.
next
()
Out[
14
]:
9
In [
15
]: g1.
next
()
Out[
15
]:
10
In [
16
]: g1.
next
()
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
StopIteration Traceback (most recent call last)
<ipython
-
input
-
16
-
9066a8f18086
>
in
<module>()
-
-
-
-
>
1
g1.
next
()
StopIteration:
|
yield本身并不是一个返回值,却能够生成一个生成器对象。
yield保存着一个对象的状态信息。(快照的例子:快照当中保存的是执行快照时的状态)
如上例所看到的,当我们在函数中使用yield,会返回一个生成器对象。
求1到20以内所有正整数的平方:
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
|
In [
17
]:
def
genNum(n):
...: count
=
1
...:
while
count <
=
n:
...:
yield
count
*
*
2
...: count
+
=
1
...:
In [
18
]: g1
=
genNum(
20
)
In [
19
]:
for
i
in
g1:
...:
print
i
...:
1
4
9
16
25
36
49
64
81
100
121
144
169
196
225
256
289
324
361
400
|
Python中的装饰器:
装饰器定义:
本质上是一个函数
功能是用来装饰其他函数。就是为其他函数添加附加功能
装饰器=高阶函数+嵌套函数
装饰器特定的原则:
不能修改被装饰的函数的源代码(线上环境)
不能修改被装饰的函数的调用方式
不能修改被装饰的函数的返回值
装饰器可以抽离出大量的函数中与函数无关的功能,把函数本身只作为一个核心,在必要时如果函数的核心功能不够,就用装饰器装饰一下本次调用所需要的功能,于是运行结束了,下次当需要其它功能时再用装饰器给重新装饰一下就可以了,这就是装饰器。
装饰器需要接受一个函数对象作为其参数,而后对此函数做包装,以对此函数进行增强。
实现装饰器的知识储备:
1、函数即“变量“(说明变量在内存中存在的方式)
2、高阶函数
a.把一个函数名当做实参传给另一个函数(可以实现在不修改被装饰函数源代码的情况下为其添加功能)
1
2
3
4
5
6
7
8
9
10
|
import
time
def
bar():
time.sleep(
3
)
print
(
'in the bar'
)
def
test1(func):
start_time
=
time.time()
func()
stop_time
=
time.time()
print
(
'The func run time is %s'
%
(stop_time
-
start_time))
test1(bar)
|
b.返回值中包含函数名(可以实现不修改被装饰函数的调用方式)
1
2
3
4
5
6
7
8
9
|
import
time
def
bar():
time.sleep(
3
)
print
(
'in the bar'
)
def
test2(func):
print
(func)
return
func
x
=
test2(bar)
#此处也可以改成:bar = test2(bar)
bar()
|
当用bar = test2(bar)时,此处定义的bar变量名就会覆盖之前定义bar函数时生成的变量名bar。
如此的话,那之前定义的bar函数进行调用时就是使用新定义的bar变量名引用其在内存中的位置,从而达到不修改bar函数调用方式的目的。
3、嵌套函数
1
2
3
4
5
6
7
|
import
time
def
foo():
print
(
'in the foo'
)
def
bar():
print
(
'in the bar'
)
bar()
foo()
|
不带参数的func(被装饰的函数):
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
In [
20
]:
def
decorative(func):
...:
def
wrapper():
#定义一个包装器
...:
print
"Please say something: "
...: func()
#调用func,这个func是我们自己定义的
...:
print
"No zuo no die..."
...:
return
wrapper
...:
In [
21
]: @decorative
#使用@符号调用装饰器
...:
def
show():
#定义func,名字取什么都无所谓,它只是用来传给装饰器中的func参数
...:
print
"I'm from Mars."
...: show()
...:
Please say something:
I'm
from
Mars.
No zuo no die...
|
如上例所示,show函数本身只有一个print语句,而使用装饰器以后,就变成了三个print,这里的print可以改成任何其它的语句,这就是函数的装饰器。
带参数的func(被装饰的函数):
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
In [
22
]:
def
decorative(func):
...:
def
wrapper(x):
...:
print
"Please say something...>"
...: func(x)
...:
print
"no zuo no die..."
...:
return
wrapper
...:
In [
23
]: @decorative
...:
def
show(x):
...:
print
x
...:
In [
24
]: show(
"hello,mars."
)
Please say something...>
hello,mars.
no zuo no die...
|
现在我们来写一个简单的为函数添加执行时间的装饰器函数:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
import
time
def
timmer(func):
def
wrapper(
*
args,
*
*
kwargs):
start_time
=
time.time()
a
=
func()
stop_time
=
time.time()
print
(
'The func run time is %s'
%
(stop_time
-
start_time))
return
a
return
wrapper
@timmer
def
foo():
time.sleep(
3
)
print
(
'in the foo'
)
print
(foo())
|
接下来再写一个现实生活中能用得到的:
需求如下:
假定有三个页面,现在要实现其中2个页面验证登录之后才能访问,另一个页面不用验证即可访问
首先定义三个页面函数:
1
2
3
4
5
6
7
8
9
|
def
index():
print
(
'Welcome to index page'
)
return
'from index page'
def
home():
print
(
'Welcome to home page'
)
return
'from home page'
def
bbs():
print
(
'Welcome to bbs page'
)
return
'from bbs page'
|
然后定义装饰器函数:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
user
=
sean
passwd
=
abc123
def
auth(auth_type
=
'local'
):
def
out_wrapper(func):
def
wrapper(
*
args,
*
*
kwargs):
if
auth_type
=
=
'local'
:
username
=
=
input
(
'Username: '
).strip()
password
=
=
input
(
'Password: '
).strip()
if
user
=
=
username
and
passwd
=
=
password:
print
(
'authentication passed'
)
func()
elif
auth_type
=
=
'ldap'
:
print
(
'This is ldap authentication'
)
func()
return
wrapper
return
out_wrapper
|
接下来将装饰器分别应用于home函数与bbs函数:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
def
index():
print
(
'Welcome to index page'
)
return
'from index page'
@auth
(auth_type
=
'local'
)
def
home():
print
(
'Welcome to home page'
)
return
'from home page'
@auth
(auth_type
=
'ldap'
)
def
bbs():
print
(
'Welcome to bbs page'
)
return
'from bbs page'
#调用函数
index()
home()
bbs()
|