Python(四) Python中的闭包函数、可变参数和装饰器

1.闭包函数

闭包函数,简而言之就是内部函数引用了外部函数中的变量。常用的方式时将函数名作为返回值返回。下面将给出例程及其注释。

1
2
3
4
5
6
7
8
9
def func():
name = 'Python' # 外部变量
def inner():
print(name)
print(inner.__closure__) # 调用内置方法查看该函数是否为闭包函数
return inner # 将函数名作为返回值
f = func() # 此时,f得到了func的返回值inner,因此f=inner
f() # 此时相当于调用了inner函数
# 输出结果为:Python

2.装饰器

2.1单个装饰器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
def w1(func):
# w1接收参数func, 实际上为一个方法名。
# w1内部定义了一个inner函数。执行完输出语句print('...验证权限...')后,
# 调用参数func,且其返回值为inner
def inner():
print('...验证权限...')
func()
return inner
# 当Python执行到@w1这句时,调用w1,同时将被装饰的函数名作为参数传入f(1)。
# 在执行w1时,返回inner函数,同时将其赋值给f1,此时,f1=w1(f1)
@w1
def f1():
print('f1 called')
f1() # 此时,相当于调用w1.inner,先输出,再执行原f1

# 输出:
# ...验证权限...
# f1 called

2.2多个装饰器

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
# 多个修饰器
def makeBold(fun):
print('----a----')
def inner():
print('----1----')
# print(fun())
return '<b>' + fun() + '</b>'
return inner
def makeItalic(fun):
print('----b----')
def inner():
print('----2----')
# print(fun())
return '<i>' + fun() + '</i>'
return inner
# 1.程序执行到@makeBold时,需要对下面的函数进行修饰,但发现下面并不是一个函数,
# 而有是一个装饰器,这时应暂停@makeBold装饰器的执行.
# 2.接着执行装饰器@makeItalic,并把ttest函数名传入装饰器函数,
# 此时先输出:----b----,并且此时的ttest指向makeItalic的inner函数地址(ttest1)
# 3.接着返回执行@makeBold,把ttest1传入makeBold装饰器函数中
# 此时输出:----a----,此时的ttest1指向makeBold.inner函数(ttest2),并输出:----1----
# 4.在ttest2中接着要调用fun()时,实际上是执行ttest1内容,
# 此时输出:----2----,并且执行ttest函数,并输出:----c----和----3----
# 同时返回结果:<i>hello python decorator</i>
# 5.接着执行ttest2未执行完成的语句,返回结果给ret:<b><i>hello python decorator</i></b>
@makeBold
@makeItalic
def ttest():
print('----c----')
print('----3----')
return 'hello python decorator'
ret = ttest()
print(ret)

2.3 对有参数函数进行装饰

2.1和2.2为对无参数函数的装饰

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
def w_add(func):
def inner(*args, **kwargs):
print('add inner called')
func(*args, **kwargs)
return inner
@w_add
def add(a, b):
print('%d + %d = %d' % (a, b, a + b))
@w_add
def add2(a, b, c):
print('%d + %d + %d = %d' % (a, b, c, a + b + c))
add(2, 4)
add2(2, 4, 6)

"""
输出结果为:
add inner called
2 + 4 = 6
add inner called
2 + 4 + 6 = 12
"""

NT:
位置参数: 当我们声明一个诸如*args的星号参数时,从此处开始直到结束的所有位置参数都将被收集并汇集成一个称为“args”的元组(Tuple)

1
2
3
4
5
6
def argsFunc(*my_args):
print(my_args)
>>> argsFunc(1, 2, 3, 4)
(1, 2, 3, 4)
>>> argsFunc()
()

关键字 参数: 当我们声明一个诸如**kwargs的双星号参数时,从此处开始直至结束的所有关键字参数都将被收集并汇集成一个名为 kwargs的字典(Dictionary)

1
2
3
4
5
6
7
8
def argsFunc(**my_args):
print(my_args)
>>> argsFunc(X=1, Y=2, Z=3)
{'X': 1, 'Y': 2, 'Z': 3}
>>> argsFunc()
{}
>>> argsFunc(1,2,3) #这种调用则报错
TypeError: argsFunc() takes 0 positional arguments but 3 were given

2.4 对带有返回值的函数进行装饰

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
def w_test(func):
def inner():
print('w_test inner called start')
str = func()
print('w_test inner called end')
return str
return inner
@w_test
def test():
print('this is test fun')
return 'hello'
ret = test()
print('ret value is %s' % ret)
"""
输出:
w_test inner called start
this is test fun
w_test inner called end
ret value is hello
"""

2.5 带有参数的装饰器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
def func_args(pre='xiaoqiang'):
def w_test_log(func):
def inner():
print('...记录日志...visitor is %s' % pre)
func()
return inner
return w_test_log
# 带有参数的装饰器能够起到在运行时,有不同的功能
# 先执行func_args('wangcai'),返回w_test_log函数的引用
# @w_test_log
# 使用@w_test_log对test_log进行装饰
@func_args('wangcai')
def test_log():
print('this is test log')
test_log()

2.6 类装饰器

当python解释器执行到到@Test时,会把当前test函数作为参数传入Test对象,调用init方法,同时将test函数指向创建的Test对象,那么在接下来执行test()的时候,其实就是直接对创建的对象进行调用,执行其call方法。

1
2
3
4
5
6
7
8
9
10
11
12
class Test(object):
def __init__(self, func):
print('test init')
print('func name is %s ' % func.__name__)
self.__func = func
def __call__(self, *args, **kwargs):
print('装饰器中的功能')
self.__func()
@Test
def test():
print('this is test func')
test()

参考链接

https://www.cnblogs.com/slysky/p/9777424.html