python 带你了解函数装饰器

装饰器基本概念

装饰器(Decorators)是 Python 的一个重要部分。简单地说:他们是修改其他函数的功能的函数。他们有助于让我们的代码更简短,也更Pythonic(Python范儿)

一切皆对象

首先我们来理解下 Python 中的函数:

def hello(name='python'):
    return 'hello '+name

print(hello())
>>> hello python

# 我们可以将一个函数赋值给一个变量(也就是说函数可以作为参数传递给其他函数),比如
a=hello
# 这里我们并没有使用小括号,并不是在调用函数,而是将它放到变量a里面,我们尝试运行下这个
print(a())
>>> hello python
# 如果我们删掉原来的hello函数,我们依然可以使用a()去调用函数
在函数中定义函数

刚才那些就是函数的基本知识了。我们来让你的知识更进一步。在 Python 中我们可以在一个函数中定义另一个函数

def hello(name='python'):

    def how():
        print('how are you?')
    
    how()
    print('hello '+name)

hello()
>>> how are you?
>>> hello python

# 当我们在调用hello()时,how()也会被调用执行
# 而内部的函数how()在hello()函数之外是不能访问的,如
how()
>>> NameError: name 'how' is not defined

现在我们知道了可以在函数中定义另外的函数。也就是说:我们可以创建嵌套的函数。

从函数中返回函数

其实并不需要在一个函数里去执行另一个函数,我们也可以将其作为输出返回出来

def hello(name='python'):

    def how():
        print('how are you?')
    
    print('hello '+name)
    return how

a=hello()
print(a)
>>> <function how at 0x000001DF1ED672F0>

# 上面清晰的展示了a现在指向how()函数
# a()则会调用how()函数
a()
>>> how are you?

再次看看这个代码。在 return语句中我们返回 how 而不是 how()。为什么那样?这是因为当你把一对小括号放在后面,这个函数就会执行;然而如果你不放括号在它后面,那它可以被到处传递,并且可以赋值给别的变量而不去执行它。

将函数作为参数传给另一个函数

在之前我们提到过可以将函数赋值给变量,那我们同样可以将其作为参数传递给另外的函数

def how():
    print('how are you?')

def hello(fun,name='python'):
    print('hello '+name)
    fun()

hello(how)
>>> hello python
>>> how are you?

在这里hello()函数就相当于一个装饰函数

第一个装饰器
def decorator(fun):
    def how():
        print('hello python')
        print('how are you?')
        fun()
    
    return how

def func():
    print('i am fine, thank you ')

a=decorator(func)
a()
>>> hello python
    how are you?
    i am fine, thank you

你看明白了吗?我们刚刚应用了之前学习到的原理。这正是 python 中装饰器做的事情!它们封装一个函数,并且用这样或者那样的方式来修改函数的的行为。下面通过使用@来使用装饰器

def decorator(fun):
    def how():
        print('hello python')
        print('how are you?')
        fun()
    
    return how

@decorator #当装饰器用来装饰某函数时,被装饰的函数名被自动传参给装饰器函数
def func():
    print('i am fine, thank you ')

func()
>>> hello python
    how are you?
    i am fine, thank you

希望你现在对 Python 装饰器的工作原理有一个基本的理解。如果我们运行如下代码会存在一个问题

print(func.__name__)
>>> how
这并不是我们想要的!Ouput输出应该是"func"。这里的函数被how替代了。
它重写了我们函数的名字和注释文档(docstring)。幸运的是Python提供给我们一个简单的函数来解决这个问题,
那就是functools.wraps。我们修改上一个例子来使用functools.wraps:
from functools import wraps

def decorator(fun):
    @wraps(fun)
    def how():
        print('hello python')
        print('how are you?')
        fun()
    
    return how

@decorator #当装饰器用来装饰某函数时,被装饰的函数名被自动传参给装饰器函数
def func():
    print('i am fine, thank you ')

print(func.__name__)
>>> how

注意:@wraps接受一个函数来进行装饰,并加入了复制函数名称、注释文档、参数列表等等的功能。这可以让我们在装饰器里面访问在装饰之前的函数的属性。

多个装饰器

一个函数还可以同时定义多个装饰器,比如:

@a
@b
@c
def f ():
    pass

它的执行顺序是从里到外,最先调用最里层的装饰器,最后调用最外层的装饰器,
它等效于f = a(b(c(f)))

递归函数装饰
# 装饰递归函数时,要注意返回值

def warp(fn):
    def nei(*args):
        print('我是装饰器')
        a=fn(*args)
        print(a)
        print('结束')
        return a
    return nei

@warp
def func1(n):
    if n<=2:
        return 1
        
    else:
        return func1(n-2)+func1(n-1)

func1(5)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值