Python/函数装饰器概念(详解)

Python中装饰器的概念


装饰器(Decorators)是 Python 的一个重要部分。简单地说:他们是修改其他函数的功能的函数。他们有助于让我们的代码更简短,也更Pythonic(Python范儿)。大多数初学者不知道在哪儿使用它们,所以我将要分享下,哪些区域里装饰器可以让你的代码更简洁。 首先,让我们讨论下如何写你自己的装饰器。

这可能是最难掌握的概念之一。我们会每次只讨论一个步骤,这样你能完全理解它。

以上来自菜鸟教程

装饰器本身就是一个函数,它只不过是对另外一个函数进行了一次封装,它能够把那个函数的功能进行一个强化

例如1:
#!/usr/bin/env python


def day1():
    print("My function name is:", day1.__name__)

def main():
    day1()

if __name__ == "__main__":
    main()
>>> My function name is: day1

在以上代码块中定义了一个函数为:day1, 输出一句话为:My function name is: day1,那么装饰器能够把原来的函数功能上进行一个强化的操作。 在以上函数中输出了一句话,若我们需要在输出一句话如:hello world 若没装饰器 如下:

#!/usr/bin/env python

def day1():
    print("hello world")
    print("My function name is:", day1.__name__)

def main():
    day1()

if __name__ == "__main__":
    main()
>>>
hello world
My function name is: day1

若有装饰器如下:

#!/usr/bin/env python


def day2(func):
    print("hello world")
    return func

@day2
def day1():
    print("My function name is:", day1.__name__)

def main():
    day1()

if __name__ == "__main__":
    main()
>>>
hello world
My function name is: day1

在以上代码块中出现了@符号,以及day2函数,现在不用管它是什么意思,以上代码已经实现了装饰器对原来的函数功能进行了一次强化,但是在第一个代码块中只需要加一句话就可以实现,但是在第二个代码中还需要在写一个函数,感觉会非常麻烦,但是如果被强化的函数有1万个,难道需要一行行去添加吗?,很显然是不可以的,所以接下来开始讲解装饰器。

一、装饰器定义

加粗样式
在定义装饰器之前首先我们需要有一个函数,因为装饰器是对函数进行了一次封装同时对函数进行强化的作用。

1.1、定义一个函数
def tony():
    print("my function name is:", tony.__name__) # 每一个函数的名字都可以自带一个变量:__name__就是函数名它自己

def main():
    tony()

if __name__ == "__main__":
    main()
> my function name is: tony # 输出内容
1.2、使用装饰器对tony函数进行增强操作
#!/usr/bin/env python

def deco_iron(func):
    print("开始运行:", deco_iron.__name__)
    return func

def tony():
    print("my function name is:", tony.__name__)

def main():
    tony()

if __name__ == "__main__":
    main()

Python/函数装饰器概念(详解)_第1张图片
将tony函数传入deco_iron函数 如下:

tony = deco_iron(tony)

Python/函数装饰器概念(详解)_第2张图片
为了更好理解tony = 换一个名称也是可以的,如下:

#!/usr/bin/env python

def deco_iron(func):
    print("开始运行:", deco_iron.__name__)
    return func

def tony():
    print("my function name is:", tony.__name__)

name = deco_iron(tony)

def main():
    name()

if __name__ == "__main__":
    main()
开始运行: deco_iron
my function name is: tony

使用@符号如下:

#!/usr/bin/env python


def deco_iron(func):
    print("开始运行:", deco_iron.__name__)
    return func

@deco_iron #---->tony = deco_iron(tony)
def tony():
    print("my function name is:", tony.__name__)

def main():
    tony()

if __name__ == "__main__":
    main()

@deco_iron 就相当于 tony = deco_iron(tony)

如何嵌套两层函数

#!/usr/bin/env python


def deco_iron(func):
    print("开始运行:", deco_iron.__name__)
    return func

def deco_iron2(func):
    print("开始运行:", deco_iron2.__name__)
    return func

@deco_iron2
@deco_iron #---->tony = deco_iron(tony)
def tony():
    print("my function name is:", tony.__name__)

def main():
    tony()

if __name__ == "__main__":
    main()
>>>
开始运行: deco_iron
开始运行: deco_iron2
my function name is: tony

@deco_iron2 等于 tony = deco_iron2(deco_iton(tony))

运行结果如下:
Python/函数装饰器概念(详解)_第3张图片

在以上例子中,将tony函数传入Deco_iron函数 只是输出了一段话就返回了tony 函数, 似乎并没有什么意义,接下来干点别的。

#!/usr/bin/env python


def deco_iron(func):
    print("开始运行:deco_iron......")
    def wrapper():
        print("开始运行wrapper..........")
        func()
        print("结束运行wrapper.............")
    return wrapper


@deco_iron #---->tony = deco_iron(tony)
def tony():
    print("my function name is:", tony.__name__)

def main():
    tony()

if __name__ == "__main__":
    main()
>>>
>开始运行:deco_iron......
开始运行wrapper..........
my function name is: wrapper
结束运行wrapper.............

可能以上代码在刚接触装饰器的时候会有点懵,不过没关系,我将会一一解读。
Python/函数装饰器概念(详解)_第4张图片

开始运行:deco_iron…
开始运行wrapper…
my function name is:wrapper 后续会解决此问题,请认真理解上图(关键!)
结束运行wrapper…

如何传入参数?

#!/usr/bin/env python


def deco_iron(func):
    print("开始运行:deco_iron......")
    def wrapper(*args, **kw):
        print("开始运行:{}".format(func.__name__))
        print(args, kw)
        func(*args, **kw)
        print("结束运行:{}".format(func.__name__))
    return wrapper


@deco_iron #---->tony = deco_iron(tony)
def tony(name, age):
    print("my function name is:", tony.__name__)
    print(f"Your name is {name}, Your age is :{age}")

def main():
    tony('yankerp', 13)

if __name__ == "__main__":
    main()
开始运行:deco_iron......
开始运行:tony
('yankerp', 13) {}
my function name is: wrapper
Your name is yankerp, Your age is :13
结束运行:tony

Python/函数装饰器概念(详解)_第5张图片
Python/函数装饰器概念(详解)_第6张图片

给装饰器传参数

#!/usr/bin/env python

def deco_params(name):
    def deco_iron(func):
        print("开始运行:deco_iron......")
        def wrapper(*args, **kw):
            print("开始运行:{}".format(func.__name__))
            print(args, kw)
            func(*args, **kw)
            print("结束运行:{}".format(func.__name__))
            print(f"My name is :{name}".center(60, "-"))
        return wrapper
    return deco_iron

@deco_params("Yankerp")
def tony(*args, **kw):
    print("my function name is:", tony.__name__)

def main():
    tony('yankerp',80)

if __name__ == "__main__":
    main()
开始运行:deco_iron......
开始运行:tony
('yankerp', 80) {}
my function name is: wrapper
结束运行:tony
--------------------My name is :Yankerp---------------------

Python/函数装饰器概念(详解)_第7张图片

解决原函数在装饰器后内存中改变的情况

#!/usr/bin/env python

from functools import wraps

def deco_params(name):
    def deco_iron(func):
        print("开始运行:deco_iron......")
        @wraps(func) # 可以理解为记住原函数的属性
        def wrapper(*args, **kw):
            print("开始运行:{}".format(func.__name__))
            print(args, kw)
            func(*args, **kw)
            print("结束运行:{}".format(func.__name__))
            print(f"My name is :{name}".center(60, "-"))
        return wrapper
    return deco_iron

@deco_params("Yankerp")
def tony(*args, **kw):
    print("my function name is:", tony.__name__)

def main():
    tony('yankerp',80)

if __name__ == "__main__":
    main()
>>>
开始运行:deco_iron......
开始运行:tony
('yankerp', 80) {}
my function name is: tony # tony
结束运行:tony
--------------------My name is :Yankerp---------------------

Python/函数装饰器概念(详解)_第8张图片
以上的操作需要三个函数的嵌套,改写成类class

#!/usr/bin/env python


from functools import wraps


class DecoIron:
    def __init__(self, name):
        self.name = name
    
    def __call__(self, func):
        @wraps(func)
        def wrapper(*args, **kw):
            print("hello world") # 输出一个hello world
            print(*args, **kw)
            func(*args, **kw) # 我们将用户传进来的函数进行返回 那么返回的这个函数 就是function
            print(f"My name is:{self.name}".center(60, "-"))
        return wrapper

@DecoIron('yankerp')
def tony(*args, **kw):
    print("my function is:{}".format(tony.__name__))

if __name__ == "__main__":
    tony('yankerp', 40)
>>>
hello world
yankerp 40
my function is:tony
---------------------My name is:yankerp---------------------

例1: 使用装饰器做一个日志输出

#!/usr/bin/env python

from functools import wraps

class Dlog:
    def __init__(self, file_name):
        self.file_mame = file_name
    
    def __call__(self, func):
        @wraps(func)
        def warpper(*args, **kw):
            str_log = "函数{}开始运行了....".format(func.__name__)
            with open(self.file_mame, 'a', encoding='utf8') as f:
                print(str_log)
                f.write(str_log + '\n')
            func(*args, **kw)
        return warpper

@Dlog('yankerp.log')
def tony(*args, **kw):
    print("my function is:{}".format(tony.__name__).center(60, "="))

if __name__ == "__main__":
    tony()
> 函数tony开始运行了....
====================my function is:tony=====================

Python/函数装饰器概念(详解)_第9张图片

使用装饰器实现函数用时

#!/usr/bin/env python

import time
from functools import wraps


class Chatends:
    def __init__(self, funcname=''):
        self.funcname = funcname
    
    def __call__(self, func):
        @wraps(func)
        def wrapper(*args, **kw):
            print("开始运行{}函数".format(func.__name__).center(60, "-"))
            start_time = time.time()
            func(*args, **kw)
            result_time = time.time() - start_time
            print(f"函数{func.__name__}运行结束,运行时间为:{int(result_time)}秒.....")
        return wrapper


@Chatends()
def tony():
    print("My function name is:{}".format(tony.__name__))
    time.sleep(3)

@Chatends()
def tony2():
    print("My function name is:{}".format(tony2.__name__))
    time.sleep(5)


if __name__ == "__main__":
    tony()
    tony2()
>>>
-------------------------开始运行tony函数-------------------------
My function name is:tony
函数tony运行结束,运行时间为:3.....
------------------------开始运行tony2函数-------------------------
My function name is:tony2
函数tony2运行结束,运行时间为:5.....

Python/函数装饰器概念(详解)_第10张图片

多种功能操作

#!/usr/bin/env python

from functools import wraps


class Chatends:
    def __init__(self, funcname, filename='yankerp.log'):
        self.funcname = funcname
        self.filename = filename
    
    def __call__(self, func):
        @wraps(func)
        def wrapper(*args, **kw):
            if hasattr(self, self.funcname):
                my_func = getattr(self, self.funcname)
                if (my_func(func)):
                    func(*args, **kw)
        return wrapper
    
    def log(self, func):
        str_log = "函数{}开始运行了....".format(func.__name__)
        with open(self.filename, 'a', encoding='utf8') as f:
            print(str_log)
            f.write(str_log + '\n')
        return True
    
    def check(self, func):
        str_log = "函数{}开始运行了....".format(func.__name__)
        print(str_log)
        user_name = input("user_name>>>")
        user_password = input("user_password>>>")
        if user_name == "yankerp" and user_password == "pwd123":
            return True
        else:
            return False


@Chatends('check')
@Chatends('log')
def tony():
    print("这是主功能函数...........".center(60, "="))

@Chatends('check')
@Chatends('log')
def tony2():
    print("这是主功能函数222...........".center(60, "="))

if __name__ == "__main__":
    tony()
    tony2()

Python/函数装饰器概念(详解)_第11张图片

你可能感兴趣的:(Python)