闭包
- 这是我的一个函数,需要为其添加许多新的功能,假如里面有几百行代码,但需要在不改变其原有的代码条件下进行。
def my_func():
print('this is my func ...')
- 那么现在想到的就是使用一个嵌套函数,传入一个函数对象给外函数,外函数返回内函数的调用, 然后传入函数对象给内函数,然后调用该函数,于是完成了不改变原有函数的条件下,添加了新的功能。
def func_outer(func):
print('this is outer func ...')
def func_inner(*arg, **kwargs):
# 可以在内函数中添加新的功能
print('this is inner func')
return func()
return func_inner
f = func_outer(my_func)
f()
- 可以看到运行顺序如下:
this is outer func ...
this is inner func
this is my func ...
装饰器
- 但是实际开发的过程中,代码都这样写的话,会显得代码有些冗余,这个时候就可以使用到装饰器这么一个东西,使用起来也十分的简单,如下:
def func_outer(func):
print('this is outer func ...')
def func_inner(*arg, **kwargs):
print('this is inner func')
return func()
return func_inner
@func_outer
def my_func():
print('this is my func ...')
# my_func()
- 结果如下,没有调用my_func函数时,func_outer便自动调用了,当调用my_func时func_inner就会自动调用,@即语法糖,将两个函数进行关联
D:\user\80005354\桌面\stupy>D:/python/python.exe d:/user/80005354/桌面/stupy/1-装饰器.py
this is outer func ...
- 同时,还可以为装饰器添加参数,即在在装饰器上再封装一个装饰器用来传递参数,只需要将内层的函数对象再次返回即可
def func_oouter(name):
def func_outer(func):
print('this is outer func ...')
def func_inner(*arg, **kwargs):
print('my name is ', name)
print('this is inner func')
return func()
return func_inner
return func_outer
@func_oouter(name='bruin')
def my_func():
print('this is my func ...')
my_func()
- 结果如下:
D:\user\80005354\桌面\stupy>D:/python/python.exe d:/user/80005354/桌面/stupy/1-装饰器.py
this is outer func ...
my name is bruin
this is inner func
this is my func ...
使用类装饰器
- 假如有一个people这个方法,也可以将people做为静态方法写入类中,但此时需要不改变people方法的同时,添加一个speak的功能。如果想让一个类使用装饰器,就得让其实现call方法能被调用,先看看普通调用方式
class Speak(object):
def __init__(self, func):
self.func = func
def __call__(self, *arg, **kwargs):
self.speak()
return self.func(*arg, **kwargs)
def speak(self):
print('I can speak now!')
def people(*arg, **kwargs):
print(kwargs['name'], 'is dance ~ ~')
speak = Speak(people)
speak(name='jack')
type(people), isinstance(people, Speak)
# 结果如下:
I can speak now!
jack is dance ~ ~
(function, False)
- 当我们使用装饰器时
@Speak
def people(*arg, **kwargs):
print(kwargs['name'], 'is dance ~ ~')
p = people(name='jack')
type(people), isinstance(people, Speak)
# 结果如下:
I can speak now!
jack is dance ~ ~
(__main__.Speak, True)
可以看到在使用装饰器之后,people已经不是原来的那个people了,此时我们可以使用functools.wraps方法保留people原有的属性。
functools.wraps
import functools
class Speak(object):
def __init__(self, *args, **kwargs):
print(args)
def __call__(self, func):
@functools.wraps(func)
def inner_wraps(*arg, **kwargs):
self.speak()
return func(*arg, **kwargs)
return inner_wraps
def speak(self):
print('I can speak now!')
@Speak(1,2)
def people(*arg, **kwargs):
print(kwargs['name'], 'is dance ~ ~')
people(name='jack')
type(people), isinstance(people, Speak)
# 结果如下
(1, 2)
I can speak now!
jack is dance ~ ~
(function, False)