一. 装饰器的应用
概念回顾
什么是装饰器?
装饰器是一个函数,主要作用是用来包装另一个函数或类。即在不改变原函数名或类名的情况下,改变被包装对象的行为。
函数装饰器及应用
函数装饰器?
函数装饰器的本质是一个闭包,接收一个函数作为参数,返回的是内部嵌套函数。
示例 1:函数装饰器的基本用法
def my_deco(fn):
def fx():
print("my_func函数被调用之前...")
fn()
print("my_func函数被调用之后...")
return fx
@my_deco
def my_func():
print("函数my_func被调用")
运行结果:
>> my_func()
my_func函数被调用之前...
函数my_func被调用
my_func函数被调用之后...
@my_deco
用来将 my_func
绑定装饰器函数 my_deco
的返回值。decorator
装饰器本身是一个闭包,接收一个函数,返回另一个函数。因此,函数一旦被装饰,真正调用的将会是装饰器函数的返回值(装饰器返回一个函数)。
示例 2:装饰器函数内部,嵌套函数外部的代码,只在装饰器初始化时执行一次
def my_deco(fn):
print("装饰器函数被调用了...")
fn()
def fx():
print("fx 被调用")
return fx
@my_deco
def my_func():
print("函数 my_func 被调用!")
运行结果:
装饰器函数被调用了...
函数 my_func 被调用!
>> my_func()
fx 被调用
在 @my_dec
装饰 my_func
时,装饰器函数 my_deco
被调用,打印 函数 my_func 被调用!
。之后,由于 my_func
引用已经指向了装饰器函数my_deco
的返回值,再调用 my_func
时实则调用的都是 fx
函数了。
示例 3:在银行存取款功能基础上,添加身份验证
def identity_check(fn):
def fx(name, x):
print("正在进行身份验证...")
fn(name, x)
return fx
@identity_check
def save_money(name, x):
print("{} 存钱 {} 元。".format(name, x))
@identity_check
def with_draw(name, x):
print("{} 取钱 {} 元。".format(name, x))
运行结果:
>> save_money("Alex", 100)
正在进行身份验证...
Alex 存钱 100 元。
>> with_draw("Alex", 100)
正在进行身份验证...
Alex 取钱 100 元。
可见,装饰器在不改变原函数和调用者行为的情况下,可用来改变原有函数功能。
示例 4:在取钱函数上再添加一个装饰器,完成取钱后的短信通知功能
def identity_check(fn):
def fx(name, x):
print("正在进行身份验证...")
fn(name, x)
return fx
def send_message(fn):
"""再增加一个装饰器函数,在取钱后添加余额变动提醒功能"""
def fy(name, x):
fn(name, x)
print("send message -¥{} changed.".format(x))
return fy
@identity_check
def save_money(name, x):
print("{} 存钱 {} 元。".format(name, x))
@send_message
@identity_check
def with_draw(name, x):
print("{} 取钱 {} 元。".format(name, x))
运行结果:
>> save_money("Alex", 100)
正在进行身份验证...
Alex 存钱 100 元。
>> with_draw("Alex", 100)
正在进行身份验证...
Alex 取钱 100 元。
send message -¥100 changed.
@identity_check
先于 @send_message
装饰 with_draw
,故 identity_check
的返回函数将优先被调用。
二. 函数的文档字符串
函数的文档字符串是函数内第一个未赋值给任何变量的字符串,用来说明函数的功能和使用方法:
- 函数的
__doc__
属性用来记录函数的文档字符串; - 函数的
__name__
属性用来记录函数的名称。
def hello():
"""这里是hello函数的文档字符串
此函数用来打招呼
"""
pass
运行结果:
>> print(hello.__name__)
hello
>> print(hello.__doc__)
这里是hello函数的文档字符串
此函数用来打招呼
>> print(help(hello))
Help on function hello in module __main__:
hello()
这里是hello函数的文档字符串
此函数用来打招呼
None
三. 可变类型作为函数参数
示例 1:
L = [1, 2, 3]
def append_print(n=0, lst=[]):
lst.append(n)
print(lst)
运行结果:
>> append_print(4, L)
[1, 2, 3, 4]
>> append_print(5, L)
[1, 2, 3, 4, 5]
>> append_print(1)
[1]
>> append_print(1)
[1, 1]
list
属于可变类型,在传递过程中,将变量的引用进行传递,因此函数内部可以直接对全局作用域的可变类型进行修改。关于参数 lst
的默认值设定:lst=[]
在函数初始化时将在内存中创建一个空的列表,而每次调用append_print
时,都将修改此列表的内容。
可变数据类型作为函数参数时,若要指定默认值,应使用 lst=None
的形式,并在函数内部创建一个全新的列表:
L = [1, 2, 3]
def append_print(n=0, lst=None):
if lst is None:
lst = []
lst.append(n)
print(lst)
运行结果:
>> append_print(4, L)
[1, 2, 3, 4]
>> append_print(5, L)
[1, 2, 3, 4, 5]
>> append_print(1)
[1]
>> append_print(1)
[1]