面试官:你知道Python装饰器如何使用吗?

446 阅读2分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第16天,点击查看活动详情

前言

说说对Python装饰器的理解,相信是很多人在面试中会遇到的问题。你可能会说,装饰器是Python一种语法糖的形式,可以放在其他函数前,这样起到不改代码增加额外功能。这样说是对的,这篇我们往细里说,看看装饰器是如何使用的。

装饰器的定义

装饰器在本质上还是一个函数,也就是我们熟知的闭包,装饰器的返回值也是一个函数对象。在Python中装饰器应用场景有很多,比如说日志的插入操作、权限校验等。

装饰器的基本写法

装饰器有很多种写法,首先我们来看看最基本的一种写法:

import time
def cost_time(func):
	def wrapper():
        st = time.time()
        func()
        et = time.time()
        c_t = et - st
        print('本次调用用时{}'.format(c_t))
    return wrapper

# 使用装饰器
@cost_time
def test():
    print('测试一下啦')
    time.sleep(3)

test()

例子很简单,装饰器的功能是打印一个函数的执行时间。来看看结果,打印出了具体耗时。

In [7]: test()
测试一下啦
本次调用用时3.004469156265259

装饰器能带参数吗

装饰器能带参数吗?答案是可以的。带参数的场景有2种:

  • 一种是装饰器本身带参数
  • 另一种是装饰器中获取被装饰函数的参数

装饰器本身带参数

在有些场景,我们需要在装饰器中带某些参数。比如需要待根据参数来执行不同代码,就需要获取参数了。使用方法也很简单,看例子:

def dec(animal):
    def print_dec(func):
        def wrapper(*args, **kwargs):
            func(*args)
            if animal == "猫":
                msg = "喵喵喵"
            elif animal == "狗":
                msg = "汪汪汪"
            print(msg)
        return wrapper
    return print_dec


@dec("猫")
def cat_yell():
	print("我是猫")
 
@dec("狗")
def dog_yell():
	print("我是狗") 

cat_yell()
dog_yell()

具体写法就是将装饰器再嵌套一层,在最外层获取参数,然后在被装饰函数外调用装饰器时将参数带上。

装饰器获取被装饰函数的参数

获取被装饰函数的参数,可通过args和kwargs来获取。直接看例子再讲解:

def dec(func):
    def wrapper(*args, **kwargs):
        print(*args)
        print(**kwargs)  
        return func(*args, **kwargs)
    return wrapper


@dec
def test(a, b):
    print("位置参数")

@dec
def test_1(a=1,b=2):
    print("关键字参数")

test(1, 2)
test_1(3, 4)

传参方式可以是位置参数,也可以是关键字参数。在装饰器内用*args、 **kwargs来接收即可。

小结

Python装饰器在生产中应用非常广泛,我们可以在很多需要附加功能的地方使用到。当然一个函数中也可同时使用多个装饰器,装饰器的调用顺序是需要注意的。