python装饰器

162 阅读3分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第8天

装饰器

装饰器是程序开发中经常会用到的一个功能,用好了装饰器,开发效率会如虎添翼,所以这也是python面试中必问的题,但对于好多初次接触这个功能的人而言,这个功能很难理解。

  • 先明白这段代码
def foo():
    print('foo')

foo #表示函数
foo() #表示调用函数
>>>>>>>>>>>> 以上是之前学过的,都应该能理解
def foo():
    print('foo')
 
foo = lambda x: x+1
foo() #执行lambda表示式,而不是foo函数,因为此时foo已经指向另一个匿名函数了

注意:函数名只是个变量,它指向你原来定义的那个函数,如果给函数名赋予其他的值,那么函数的功能就会改成你所赋予的那个值

需求

若一个项目已经有了底层基础的代码可以实现基础功能,此时我们还要加一个新功能(例如:验证功能),我们就要遵循封闭开放原则,这时我们就需要用到装饰器

  1. 封闭:对于以实现功能的代码块
  2. 开放:对于拓展开发

以上意思就是我们不能在原有的代码块上进行修改,我们得保证原有功能代码块的情况下进行拓展的添加

装饰器

通常闭包定义,@进行调用

定义

def xxx(func):
    def xxx(参数,....):
        ...
        func()
        ...
        return xxx
    return xxx
def docorators(func): #这里的参数是为了把底下的house函数拿过来
    def wapper():
        func()    #这里是为了调用house这个函数
        print('刷漆')
        print('铺地板')
        print('买家具')
        print('精装房子')
	return wapper

@docorators
def house():
    print('毛坯房')

house()

>>>>>>
毛坯房
刷漆
铺地板
买家具
精装房子

image-20220413200846232.png

注意:这里的返回值由house来接管,这一点非常重要

@装饰器名 ---> 原函数 = 装饰(原函数)

装饰器的功能

  1. 引入日志
  2. 函数执行时间统计
  3. 执行函数前预备处理
  4. 执行函数后清理功能
  5. 权限校验等场景
  6. 缓存

带参数的装饰器

def docorators(func): #这里的参数是为了把底下的house函数拿过来
    def wapper(*args,**kwargs): #这里的参数实际就是传的北京,记住这里返回的是元组,所以必须拆包
        func(*args**kwargs)    #这里是为了调用house这个函数
        print('刷漆')
        print('铺地板')
        print('买家具')
        print('精装房子')
	return wapper

@docorators
def house(address):
    print('房子在{}'.format(address))

@docorators
def changfang(address,area):
    print('房子在{},{}平方米'.format(address,area))

house('北京')
changfang('北京',1000)

这里的基础函数和装饰器的子函数以及调用函数的参数必须统一(因为这里的参数可能是多变的,为了实现装饰器的复用,我们可以把参数改成*args**kwargs,然后进行拆包)

装饰器中的return

def docorators(func): 
    def wapper(*args,**kwargs):
        a = func(*args**kwargs)
        print('刷漆')
        print('铺地板')
        print('买家具')
        print('精装房子')
		return a
    return wapper
@docorators
def house(address,price):
    print('房子在{}'.format(address))
    return price
r = house('北京',10000)
print(r)

如果装饰器所装饰的函数带有返回值,那么我们就必须让装饰器的子函数带上返回值

装饰器也能带参数

def outer(time):
    def check(action):
        def do():
            if time < 22:
                return action()
            else:
                return '对不起,您不具有权限'
		return do
    return check

@outer(23)
def play():
    return '玩个游戏'
print(paly())

带参数的装饰器相当于把装饰器作为内部函数闭包

image-20220413220819790.png