IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Python知识库 -> python之装饰器 -> 正文阅读

[Python知识库]python之装饰器

能接受一个函数的函数或者类,可以当做一个装饰器,这个函数需要返回一个函数(并不是函数的调用),函数的参数应于被修饰的函数的参数相同

条件

能作为装饰器的函数应该具有以下特征

  1. 函数需要接受一个函数作为参数
  2. 函数需要返回一个函数,返回的函数的参数应于被修饰的函数的参数相同
    1. 注意是返回函数,而不是返回函数的调用
    2. @就相当于执行返回的函数,也就是说@后面的函数先执行一次,拿到返回的函数,饭后执行返回的函数
  • 在执行函数的时候,其实是在执行装饰器返回的函数,装饰器下面的函数,只是装饰器的参数

装饰器的简单使用

代码

def decorator(func): 
    def make_decorator():
        print('现在开始装饰')
        func()
        print('现在结束装饰')
    return make_decorator
 
@decorator
def test():
    print('i am test')

# 执行函数
test()

效果

现在开始装饰
i am test
现在结束装饰

装饰器传参

代码

def decorator(*args,**kwargs): 
    def start_decoration(func):
        def make_decorator():
            print(args,kwargs)
            print('现在开始装饰')
            func()
            print('现在结束装饰')
        return make_decorator
    return start_decoration
 
@decorator("hello world")
def test():
    print('i am test')

# 执行函数
test()

打印如下

('hello world',) {'name': 'hello'}
现在开始装饰
i am test
现在结束装饰

代码的解释

  • 因为装饰器需要传参,就需要类似的这种形式传参@decorator("hello world")
  • 他会先进行decorator("hello world")函数的调用,而@后面也需要一个函数(不是一个函数的调用),这个函数需要满足装饰器的条件
    • 所以在decorator("hello world")中需要返回一个函数,所以返回了start_decoration
    • 这个时候@拿到的就是start_decoration这个函数
    • start_decoration满足装饰器的条件
  • 而作为装饰器的函数的内部,也可以拿到我们通过装饰器传的参数

多个装饰器

代码

def decorator1(func):
    def make_decorater(*args,**kwargs): 
        print('decorator1 start')
        test_func = func(*args,**kwargs) 
        print('decorator1 end') 
        return test_func 
    return make_decorater
 
def decorator2(func):
    def make_decorater(*args,**kwargs):  
        print('decorator2 start')
        test_func = func(*args,**kwargs)  
        print('decorator2 end')
        return test_func  
    return make_decorater
 
@decorator1
@decorator2
def test():
    print('我是被装饰的函数')

test()

结果

decorator1 start
decorator2 start
我是被装饰的函数
decorator2 end
decorator1 end

知识点

先装饰,后执行

根据结果我们可以看出,被装饰的函数test大概被装饰城了下面的样子

def decorated_test():
    ret = None
    print('decorator1 start')
    print('decorator2 start')
    ret = test()
    print('decorator2 end')
    print('decorator1 end') 
    return ret

装饰的顺序

  • 从下往上装饰,也就是说decorator2先进行装饰,decorator1拿到decorator2装饰后的结果之后,再进行装饰

执行的顺序

  • 执行的时候,我们大致可以看成从上往下执行

类装饰器

类装饰器比较容易理解,类装饰器是专门用于装饰类的,作为装饰器的可以是一个函数,也可以是一个类

条件

可以简单的记为,给谁装饰就要返回谁(给函数装饰,最终返回函数,给类装饰,最终要返回类)

  1. 需要接受一个类为参数
  2. 需要返回当前的类

例子

代码

def decorator(cls):             # 传入一个类即cls
    cls.name = "decorator_name"     # 设置一个类属性
    return cls    

@decorator
class Animal:
    pass

animal = Animal()
print(animal.name)

效果

会打印出decorator_name

类作为装饰器

  1. 当我们调用装饰器进行传参的时候,他会将类进行调用(实例化),实例化后还会进行一次调用,实例需要是一个可调用的对象,那么就必须加上__call__方法
  2. 这个__call__方法有一些要求
    1. 他接收函数作为参数,这个函数就是我们装饰的函数
    2. 返回一个函数,返回函数的参数应于被装饰的函数相同

代码

作为函数装饰器

from cgi import print_arguments
from typing import Any


class Decorator:

    def __init__(self, name) -> None:
        self.name = name

    def __call__(self, func, *args: Any, **kwds: Any) -> Any:
        print('调用了Decorator的__call__')
        print(f"装饰器的名字{self.name}")

        def inner(foo_self, *args):  # 返回的函数参数应于被装饰的函数相同
            print(foo_self.name)
            print("我是装饰后的函数")
            return func(foo_self, *args)

        return inner


descirber = Decorator

class Foo:

    def __init__(self):
        self.name = 'Foo class'

    @descirber('Decorator') 
    def foo(self):
        return 'Foo 实例上的 foo'


f = Foo() # 当类进行实例化的时候,他就会调用装饰器进行装饰
print(f.foo())

作为类装饰器

秉承原则:给谁装饰就要返回谁

class Class_decorator:
    def __init__(self,cls) -> None:
        self.cls = cls

    def __call__(self, *args: Any, **kwds: Any) -> Any:
        self.cls.name = "Class_decorator_name"
        return self.cls


@Class_decorator
class Animal:
    pass


animal = Animal()
print(animal.name)

注意事项

  • 类作为类装饰器的时候,类作为参数的时候,是通过__init__传递的
  • 但实质上,当我们的装饰器需要传参的时候,想要拿到这个类,我们应该在__call__这个方法中拿到。当不需要传参的时候,想要拿到这个类,就应该在__init__中拿到
  Python知识库 最新文章
Python中String模块
【Python】 14-CVS文件操作
python的panda库读写文件
使用Nordic的nrf52840实现蓝牙DFU过程
【Python学习记录】numpy数组用法整理
Python学习笔记
python字符串和列表
python如何从txt文件中解析出有效的数据
Python编程从入门到实践自学/3.1-3.2
python变量
上一篇文章      下一篇文章      查看所有文章
加:2022-05-08 08:03:10  更:2022-05-08 08:04:42 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/15 15:23:48-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码