Python中的装饰器

装饰器主要用途是包装另一个函数或者类。这种包装主要是为了透明地修改或者增强被包装对象的行为。装饰器的语法是特殊符号@——这是《Python参考手册》里面描述的。

装饰器其实就是一个函数,这个函数将另一个函数或者类作为参数,并返回经过处理的类或者函数。下面讨论一下装饰器的具体用法,即大家在实际想要使用装饰器的时候到底怎么写呢。

首先我想说的是当用装饰器函数去装饰一个函数的时候可以将装饰器分为是否接受参数,什么意思?请看下面的例子

@trace
def squre(x):
    return x*x
这种就是没有接受参数的装饰器

@trace(1)
def squre(x):
    return x*x

上面这种情况就是接受参数的

上面这两种情况表示什么意思呢,《Python参考手册》就说的很好,其分别对应下面的代码

def square(x):

  return x*x

square=trace(square)#先调用trace函数,注意square名字现在指向了经过装饰的square函数,原来的square函数对象被也被保存起来了,至于保存在哪儿了,为了不让读者绕晕,这里暂时不扯了

def square(x):
  return x*x
temp=trace(1)
square=temp(square)   

从上面两段代码的第一个代码可以看出来,如果想要定义一个装饰器函数去修饰另一个函数,必须要将函数对象作为返回值,而且要将被装饰的函数作为参数。于是装饰器函数就很好写了,请看下面的代码

def trace(func):  #接受一个函数对象作为参数
    def callf(*args,**kv):  #这里用位置参数和键参数来接受无法预知的函数对象的参数
        return func(*args,**kv)  #顺理成章地将位置参数和键参数传递给函数对象
    return callf  #返回经过装饰的函数对象

但是当你刚刚说的个条件用在带参数的装饰器就说不通了,带参数的装饰器很显然没有接受一个函数对象作为参数。但是有一点是肯定的就是必须返回一个被装饰了的函数对象,但是我们也可以使用逆向思维的方法,根据《Python参考手册》给出的装饰器的等价代码去实现一个装饰器

def trace(num):
    if num:
        def func(fun):#作为返回的中间存储的temp函数对象
            def inner(*args,**kv):#这里就不带参数的装饰器的实现方法
                print "Hello world"
                return fun(*args,**kv)
            return inner
        return func

现在把写一个函数的装饰器的方法整理一下:

1、不带参的装饰器
  a)将被装饰的函数对象作为参数(只接受一个函数对象作为参数)
  b)在装饰函数中定义一个包装函数
  c)在包装函数中适当的调用被装饰的函数
  d)将这个装饰函数对象返回

2、带参的装饰器
   a)在原来的不带参的装饰器的基础上再定义一个外层的处理参数的函数,内层函数会默认接受一个被装饰的函数对象作为参数

为了证明上述逆向思维的正确性,我现在举几个异想天开的例子去针对带参的装饰器
  1)内层函数不光接受一个函数作为参数

def trace(switch):
    if switch:
        def func(fun,a)#报错中的113行
            def inner(*args,**kv):
                print 'Hello world'
                return fun(*args,**kv)
            return inner
        return func
@trace(1)
def fun(a):
  return a*a

在Python的shell中运行时报错:
Traceback (most recent call last):
  File "<pyshell#113>", line 1, in <module>
    @trace(1)
TypeError: func() takes exactly 2 arguments (1 given)###产生这种错位因为func只能接受一个参数,因为解释器只会传一个参数给他

以下是一些常见的 Python 装饰器面试问题及其回答: 1. 什么是装饰器装饰器Python 中一种高级的语法结构,它允许在不修改原函数代码的情况下,对函数进行增强或修改。装饰器本质上是一个函数,它接收一个函数作为参数,并返回一个函数。 2. 装饰器有哪些应用场景? 装饰器可以用于实现各种功能,如: - 日志记录:记录函数的调用时间、输入参数、输出结果等信息。 - 计时器:统计函数的运行时间。 - 缓存:缓存函数的输出结果,避免重复计算。 - 权限验证:验证用户是否有权调用函数。 - 接口限流:限制函数的调用频率。 3. 装饰器的语法是什么? 装饰器的语法如下: ```python @decorator def func(): pass ``` 其中,`decorator` 是装饰器函数,`func` 是被装饰函数。装饰器函数可以在函数执行前后对函数进行修改或增强。如果需要传递参数,可以使用带参数的装饰器,如: ```python @decorator(arg1, arg2, ...) def func(): pass ``` 4. 装饰器的执行顺序是怎样的? 多个装饰器会按照从下往上的顺序依次执行,即先执行最外层的装饰器,然后执行内层的装饰器,最后执行被装饰的函数。例如: ```python @a @b @c def func(): pass ``` 执行顺序为 `func = a(b(c(func)))`。 5. 装饰器中如何传递参数? 装饰器可以使用带参数的形式,例如: ```python def my_decorator(arg1, arg2): def decorator(func): def wrapper(*args, **kwargs): # 在这里对函数进行增强或修改 return func(*args, **kwargs) return wrapper return decorator @my_decorator(arg1, arg2) def my_func(): pass ``` 在这个例子中,`my_decorator` 是一个带参数的装饰器,它接收两个参数 `arg1` 和 `arg2`。`decorator` 是一个不带参数的装饰器函数,它接收一个函数作为参数,并返回一个函数。`wrapper` 是被返回的函数,它接收任意数量的位置参数和关键字参数,并在其中对函数进行增强或修改。最后,使用 `@my_decorator(arg1, arg2)` 语法将装饰器应用到函数上。 6. 装饰器中如何保留被装饰函数的元信息? 当使用装饰器时,有时候需要保留被装饰函数的元信息,例如函数名、文档字符串等。为了实现这个功能,可以使用 `functools.wraps` 装饰器,它可以将被装饰函数的元信息复制到装饰器函数中。例如: ```python import functools def my_decorator(func): @functools.wraps(func) def wrapper(*args, **kwargs): # 在这里对函数进行增强或修改 return func(*args, **kwargs) return wrapper @my_decorator def my_func(): """这是一个示例函数""" pass ``` 在这个例子中,使用 `@functools.wraps(func)` 语法将被装饰函数的元信息复制到 `wrapper` 函数中。这样,当调用 `help(my_func)` 时,可以看到函数的文档字符串和函数名。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值