Python编程-函数装饰器Decorators


部分参考:

Python 函数装饰器 | 菜鸟教程
CSDN:python装饰器详解

1.函数装饰器的功能概况

简言之,python装饰器就是用于拓展原来函数功能的一种函数,这个函数的特殊之处在于它的返回值也是一个函数,使用python装饰器的好处就是在不用更改原函数的代码前提下给函数增加新的功能。

2.函数的调用和定义

2.1.简单的函数定义

def hi(name="yasoob"):
    return "hi " + name
 
print(hi())
# output: 'hi yasoob'
 
# 我们甚至可以将一个函数赋值给一个变量,比如
greet = hi
# 我们这里没有在使用小括号,因为我们并不是在调用hi函数
# 而是在将它放在greet变量里头。我们尝试运行下这个
 
print(greet())
# output: 'hi yasoob'
 
# 如果我们删掉旧的hi函数,看看会发生什么!
del hi
print(hi())
#outputs: NameError
 
print(greet())
#outputs: 'hi yasoob'

2.2.函数的嵌套定义

在函数中定义函数:

def hi(name="yasoob"):
    print("now you are inside the hi() function")
 
    def greet():
        return "now you are in the greet() function"
 
    def welcome():
        return "now you are in the welcome() function"
 
    print(greet())
    print(welcome())
    print("now you are back in the hi() function")
 
hi()
#output:now you are inside the hi() function
#       now you are in the greet() function
#       now you are in the welcome() function
#       now you are back in the hi() function
 
# 上面展示了无论何时你调用hi(), greet()和welcome()将会同时被调用。
# 然后greet()和welcome()函数在hi()函数之外是不能访问的,比如:
 
greet()
#outputs: NameError: name 'greet' is not defined

2.3.函数中返回函数

ef hi(name="yasoob"):
    def greet():
        return "now you are in the greet() function"
 
    def welcome():
        return "now you are in the welcome() function"
 
    if name == "yasoob":
        return greet
    else:
        return welcome
 
a = hi()
print(a)
#outputs: <function greet at 0x7f2143c01500>
 
#上面清晰地展示了`a`现在指向到hi()函数中的greet()函数
#现在试试这个
 
print(a())
#outputs: now you are in the greet() function

这里需要注意的是:在 if/else语句中我们返回 greetwelcome,而不是 greet()welcome()。因为当你把一对小括号放在后面,这个函数就会执行;然而如果你不放括号在它后面,那它可以被到处传递,并且可以赋值给别的变量而不去执行它
例如:当我们执行hi()()时,相当于首先执行hi(),此时hi()返回greet,再加一个小括号,相当于执行greet()

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

def hi():
    return "hi yasoob!"
 
def doSomethingBeforeHi(func):
    print("I am doing some boring work before executing hi()")
    print(func())
 
doSomethingBeforeHi(hi)
#outputs:I am doing some boring work before executing hi()
#        hi yasoob!

这里的doSomethingBeforeHi在每个被传入的函数执行之前都会打印一句话来指示正在执行的程序

3.装饰器的使用

3.1.一个类似装饰器的函数嵌套调用

def a_new_decorator(a_func):
 
    def wrapTheFunction():
        print("I am doing some boring work before executing a_func()")
 
        a_func()
 
        print("I am doing some boring work after executing a_func()")
 
    return wrapTheFunction
 
def a_function_requiring_decoration():
    print("I am the function which needs some decoration to remove my foul smell")
 
a_function_requiring_decoration()
#outputs: "I am the function which needs some decoration to remove my foul smell"
 
a_function_requiring_decoration = a_new_decorator(a_function_requiring_decoration)
#now a_function_requiring_decoration is wrapped by wrapTheFunction()
 
a_function_requiring_decoration()
#outputs:I am doing some boring work before executing a_func()
#        I am the function which needs some decoration to remove my foul smell
#        I am doing some boring work after executing a_func()

a_new_decorator的作用就是在特定函数执行前后都打印一句话来指示函数将要执行和执行完毕,当我们希望每一次的调用函数都使用这两个指示,最基础的做法就是调用```a_new_decorator``将要使用的函数作为参数传入,也就是上述的

a_new_decorator(a_function_requiring_decoration)

3.2.使用装饰器简化调用

def a_new_decorator(a_func):
 
    def wrapTheFunction():
        print("I am doing some boring work before executing a_func()")
 
        a_func()
 
        print("I am doing some boring work after executing a_func()")
 
    return wrapTheFunction
@a_new_decorator
def a_function_requiring_decoration():
    """Hey you! Decorate me!"""
    print("I am the function which needs some decoration to "
          "remove my foul smell")
 
a_function_requiring_decoration()
#outputs: I am doing some boring work before executing a_func()
#         I am the function which needs some decoration to remove my foul smell
#         I am doing some boring work after executing a_func()
 
#the @a_new_decorator is just a short way of saying:
a_function_requiring_decoration = a_new_decorator(a_function_requiring_decoration)

在函数a_function_requiring_decoration()的定义前有这么一句@a_new_decorator,这就是装饰器,我们会发现,在直接调用a_function_requiring_decoration()时,就会打印我们期望的指示函数调用的两句话,类似于:
在函数a_function_requiring_decoration()的定义前加上@a_new_decorator,在执行a_function_requiring_decoration()时,默认执行的是@a_new_decorator(a_function_requiring_decoration)
需要注意的是,此时如果我们执行:

print(a_function_requiring_decoration.__name__)
# Output: wrapTheFunction

会发现,Ouput输出应该是"a_function_requiring_decoration",但是却输出了wrapTheFunction,我的理解是这样的:
不管是执行a_function_requiring_decoration(),还是单纯作为一个对象a_function_requiring_decoration被调用/传递,这个函数在定义前加上了@a_new_decorator,就等于它的本质已经不是a_function_requiring_decoration而是a_new_decorator(a_function_requiring_decoration),所以
a_function_requiring_decoration.__name__=a_new_decorator(a_function_requiring_decoration).__name__=wrapTheFunction.__name__
a_function_requiring_decoration()=a_new_decorator(a_function_requiring_decoration)()=wrapTheFunction()
这种情况下,装饰器的函数会重写了我们函数的名字和注释文档(docstring)

如果你不想函数被装饰器中的函数替代,可以使用Python提供给我们的一个简单的函数,那就是functools.wraps

3.3装饰器链

一个python函数也可以被多个装饰器修饰,要是有多个装饰器时,这些装饰器的执行顺序是怎么样的呢?

def decorator1(func):
	return lambda:"<1>"+func()+"<1>"

def decorator2(func):
	return lambda:"<2>"+func()+"<2>"

@decorator1
@decorator2
def func():
	return "hello"

print(func())
#<1><2>helllo<2><1>

因此,当函数被多个装饰器修饰时,执行的顺序为先执行离函数定义近的,再执行离函数定义远的

3.4.类装饰器

前面的例子都是使用本质为函数的装饰器去装饰其他的函数,其实也可以使用类的定义去定义一个装饰器

class Decorator(object):
    def __init__(self, f):
        self.f = f
    def __call__(self):
        print("decorator start")
        self.f()
        print("decorator end")

@Decorator
def func():
    print("func")

func()
#decorator start
#func
#decorator end

4.functools.wraps

from functools import wraps
 
def a_new_decorator(a_func):
    @wraps(a_func)
    def wrapTheFunction():
        print("I am doing some boring work before executing a_func()")
        a_func()
        print("I am doing some boring work after executing a_func()")
    return wrapTheFunction
 
@a_new_decorator
def a_function_requiring_decoration():
    """Hey yo! Decorate me!"""
    print("I am the function which needs some decoration to "
          "remove my foul smell")
 
print(a_function_requiring_decoration.__name__)
# Output: a_function_requiring_decoration
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值