Python函数装饰器

Python中函数的使用

在Python中,一切都可以看作一个对象,因此,函数也是一个对象。函数可以被传递给一个变量,可以作为另一个函数的参数,还可以作为函数的返回值。

  • 函数传递给变量
def Hello():
    return 'Hello'

f = func # 将函数赋值给一个变量
print(f)
print(f()) # 执行函数(在函数名后面带上括号才是执行函数)

f = func() # 执行函数,并将返回值赋值给变量f
print(f)

# 输出
# <function func at 0x7efe6450ed08>
# Hello
# Hello
  • 函数作为参数传递给另一个函数
def Hello():
    return 'Hello'

def callHello(func):
    print('Hey')
    print(func())

callHello(Hello)

# 输出
# Hey
# Hello
  • 函数作为返回值
def Hello():
    def Hi():
        return 'Hi'
    return Hi()

f = Hello()
print(f)

# 输出
# Hi

Python函数装饰器

装饰器(decorators)是一个可以对其它函数进行修改的函数。通过装饰器,不需要对原函数进行修改,提高了程序的可读性和开发效率。装饰器的使用:

def decorator(func):
    def wrapper():
        print('wrapper')
        func()
    return wrapper

@decorator
def Hello():
    print('Hello')

Hello()

# 输出
# wrapper
# Hello
# wrapper

在上面的代码中,@decorator的作用等价于下面代码中的Hello = decorator(Hello)。@decorator装饰器的作用等价与把Hello函数作为参数传给decorator函数,然后将返回值传递给Hello。而decorator函数的返回值是wrapper函数,所以,最后执行Hello()相当于执行wrapper()函数。

def decorator(func):
    def wrapper():
        print('wrapper')
        func()
    return wrapper

def Hello():
    print('Hello')

Hello = decorator(Hello)
Hello()

# 输出
# wrapper
# Hello

但是这样有一个问题,就是Hello函数实际上发生了改变,不再是原来的Hello函数,变成了wrapper函数。可以验证一下。

import functools

def decorator(func):
    def wrapper():
        print('wrapper')
        func()
    return wrapper

@decorator
def Hello():
    print('Hello')

Hello()
print(Hello.__name__)

# 输出
# wrapper
# Hello
# wrapper

为了解决这个问题,可以用内置的装饰器@functools.wrap,它会保留原函数的信息,仅仅把原函数的信息拷贝到对应的装饰器函数中。

import functools

def decorator(func):
    @functools.wraps(func)
    def wrapper():
        print('wrapper')
        func()
    return wrapper

@decorator
def Hello():
    print('Hello')

Hello()
print(Hello.__name__)

# 输出
# Hello
# Hello

带参数的Python函数装饰器

上面被装饰器修饰的函数都是未带参数,如果函数带有参数该如何处理?一个简单的方式是可以在对应的装饰器函数中带上相同数量的参数。

import functools

def decorator(func):
    @functools.wraps(func)
    def wrapper(info):
        print('wrapper')
        func(info)
    return wrapper

@decorator
def Hello(info):
    print(info)

Hello('Hello')

# 输出
# wrapper
# Hello

如果有另一个函数也需要使用decorator装饰器,但是这个函数不止一个参数,又该怎么解决呢?例如:

@decorator
def Hello(info1, info2, info3):
    ...

通常情况下,我们会使用 *arg 和 *kwargs 作为装饰器中wrapper()函数的参数,*arg 和 *kwargs 表示函数可以接受任意数量和类型的参数。这样一来,上面例子中的装饰器就可以写成这种形式:

import functools

def decorator(func):
    @functools.wraps(func)
    def wrapper(*args, **kwargs):
        print('wrapper')
        func(*args, **kwargs)
    return wrapper

@decorator
def Hello(info):
    print(info)

Hello('Hello')

# 输出
# wrapper
# Hello

装饰器的使用场景

授权(Authorization)

装饰器能有助于检查某个人是否被授权去使用一个web应用的端点(endpoint)。这里是一个例子来使用基于装饰器的授权:

from functools import wraps

def requires_auth(f):
    @wraps(f)
    def decorated(*args, **kwargs):
        auth = request.authorization
        if not auth or not check_auth(auth.username, auth.password):
            authenticate()
        return f(*args, **kwargs)
    return decorated

日志(Logging)

from functools import wraps

def logit(func):
    @wraps(func)
    def with_logging(*args, **kwargs):
        print(func.__name__ + " was called")
        return func(*args, **kwargs)
    return with_logging

@logit
def addition_func(x):
   """Do some math."""
   return x + x


result = addition_func(4)
# Output: addition_func was called

使用场景中的两个例子来源于参考资料:
https://eastlakeside.gitbooks.io/interpy-zh/content/decorators/auth.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值