正文
# 2
# 1
# 0
# 但无法作用于 集合 和 迭代器
reversed
(
iter_example
)
# TypeError: argument to reversed() must be a sequence
除此以外,还可以通过实现类里的__reversed__方法,将类进行反向迭代:
class
Countdown
:
def
__init__
(
self
,
start
)
:
self
.
start
=
start
# 正向迭代
def
__iter__
(
self
)
:
n
=
self
.
start
while
n
>
0
:
yield
n
n
-=
1
# 反向迭代
def
__reversed__
(
self
)
:
n
=
1
while
n
self
.
start
:
yield
n
n
+=
1
for
i
in
reversed
(
Countdown
(
4
))
:
print
(
i
)
# 1
# 2
# 3
# 4
for
i
in
Countdown
(
4
)
:
print
(
i
)
# 4
# 3
# 2
# 1
try/except/else/finally
函数
使用装饰器
装饰器用于在不改变原函数代码的情况下修改已存在的函数。常见场景是增加一句调试,或者为已有的函数增加log监控
举个栗子:
def decorator_fun
(
fun
)
:
def new_fun
(
*
args
,
**
kwargs
)
:
print
(
'current fun:'
,
fun
.
__name__
)
print
(
'position arguments:'
,
args
)
print
(
'key arguments:'
,
**
kwargs
)
result
=
fun
(
*
args
,
**
kwargs
)
print
(
result
)
return
result
return
new
_
fun
@
decorator_fun
def add
(
a
,
b
)
:
return
a
+
b
add
(
3
,
2
)
# current fun: add
# position arguments: (3, 2)
# key arguments: {}
# 5
除此以外,还可以编写接收参数的装饰器,其实就是在原本的装饰器上的外层又嵌套了一个函数:
def read_file
(
filename
=
'results.txt'
)
:
def decorator_fun
(
fun
)
:
def new_fun
(
*
args
,
**
kwargs
)
:
result
=
fun
(
*
args
,
**
kwargs
)
with open
(
filename
,
'a'
)
as
f
:
f
.
write
(
result
+
'\n'
)
return
result
return
new_fun
return
decorator_fun
# 使用装饰器时代入参数
@
read_file
(
filename
=
'log.txt'
)
def add
(
a
,
b
)
:
return
a
+
b
但是像上面那样使用装饰器的话有一个问题:
@
decorator_fun
def add
(
a
,
b
)
:
return
a
+
b
print
(
add
.
__name__
)
# new_fun
也就是说原函数已经被装饰器里的new_fun函数替代掉了。调用经过装饰的函数,相当于调用一个新函数。查看原函数的参数、注释、甚至函数名的时候,只能看到装饰器的相关信息。为了解决这个问题,我们可以使用 Python 自带的functools.wraps方法。
stackoverflow: What does functools.wraps do?
functools.wraps是个很 hack 的方法,它本事作为一个装饰器,做用在装饰器内部将要返回的函数上。也就是说,它是装饰器的装饰器,并且以原函数为参数,作用是保留原函数的各种信息,使得我们之后查看被装饰了的原函数的信息时,可以保持跟原函数一模一样。
from functools import wraps
def decorator_fun
(
fun
)
:
@
wraps
(
fun
)
def new_fun
(
*
args
,
**
kwargs
)
:
result
=
fun
(
*
args
,
**
kwargs
)
print
(
result
)
return
result
return
new
_
fun
@
decorator_fun
def add
(
a
,
b
)
:
return
a
+
b
print
(
add
.
__name__
)
# add
此外,有时候我们的装饰器里可能会干不止一个事情,此时应该把事件作为额外的函数分离出去。但是又因为它可能仅仅和该装饰器有关,所以此时可以构造一个装饰器类。原理很简单,主要就是编写类里的__call__方法,使类能够像函数一样的调用。
from functools import wraps
class
logResult
(
object
)
:
def __init__
(
self
,
filename
=
'results.txt'
)
:
self
.
filename
=
filename
def __call__
(
self
,
fun
)
:
@
wraps
(
fun
)
def new_fun
(
*
args
,
**
kwargs
)
:
result
=
fun
(
*
args
,
**
kwargs
)
with open
(
filename
,
'a'
)
as
f
:
f
.
write
(
result
+
'\n'
)
return
result
self
.
send_notification
()