Weibw's World Weibw's World
首页
  • HTML
  • Python

    • Python基础知识
    • Python CookBook第三版
    • Flask
  • MySQL

    • MySQL基础知识
    • MySQL调优
    • MySQL面试题
算法
  • FineReport
  • Kettle
  • Git
  • 微信公众号文章
  • 优秀博客文章
  • 其他
收藏夹
  • 分类
  • 标签
  • 归档
GitHub (opens new window)

Weibw

一个没有梦想的咸鱼
首页
  • HTML
  • Python

    • Python基础知识
    • Python CookBook第三版
    • Flask
  • MySQL

    • MySQL基础知识
    • MySQL调优
    • MySQL面试题
算法
  • FineReport
  • Kettle
  • Git
  • 微信公众号文章
  • 优秀博客文章
  • 其他
收藏夹
  • 分类
  • 标签
  • 归档
GitHub (opens new window)
  • 《Flask》

  • 《Python Cookbook》第三版

    • 第一章:数据结构与算法

    • 第二章:字符串和文本

    • 第三章:数字日期和时间

    • 第四章:迭代器与生成器

    • 第五章:文件与IO

    • 第六章:数据编码和处理

    • 第七章:函数

    • 第八章:类与对象

    • 第九章:元编程

      • 在函数上添加包装器
      • 创建装饰器时保留函数元信息
      • 解除一个装饰器
      • 定义一个带参数的装饰器
      • 可自定义属性的装饰器
      • 带可选参数的装饰器
      • 利用装饰器强制函数上的类型检查
      • 将装饰器定义为类的一部分
        • 问题
        • 解决方案
        • 讨论
      • 将装饰器定义为类
      • 为类和静态方法提供装饰器
      • 装饰器为被包装函数增加参数
      • 使用装饰器扩充类的功能
      • 使用元类控制实例的创建
      • 捕获类的属性定义顺序
      • 定义有可选参数的元类
      • args和kwargs的强制参数签名
      • 在类上强制使用编程规约
      • 以编程方式定义类
      • 在定义的时候初始化类的成员
      • 利用函数注解实现方法重载
      • 避免重复的属性方法
      • 定义上下文管理器的简单方法
      • 在局部变量域中执行代码
      • 解析与分析Python源码
      • 拆解Python字节码
    • 第十章:模块与包

    • 第十一章:网络与Web编程

    • 第十二章:并发编程

    • 第十三章:脚本编程与系统管理

    • 第十四章:测试、调试和异常

    • 第十五章:C语言扩展

  • Python基础

  • Python
  • 《Python Cookbook》第三版
  • 第九章:元编程
weibw
2022-01-14

将装饰器定义为类的一部分

# 问题

你想在类中定义装饰器,并将其作用在其他函数或方法上。

# 解决方案

在类里面定义装饰器很简单,但是你首先要确认它的使用方式。比如到底是作为一个实例方法还是类方法。 下面我们用例子来阐述它们的不同:

from functools import wraps

class A:
    # Decorator as an instance method
    def decorator1(self, func):
        @wraps(func)
        def wrapper(*args, **kwargs):
            print('Decorator 1')
            return func(*args, **kwargs)
        return wrapper

    # Decorator as a class method
    @classmethod
    def decorator2(cls, func):
        @wraps(func)
        def wrapper(*args, **kwargs):
            print('Decorator 2')
            return func(*args, **kwargs)
        return wrapper
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

下面是一使用例子:

# As an instance method
a = A()
@a.decorator1
def spam():
    pass
# As a class method
@A.decorator2
def grok():
    pass
1
2
3
4
5
6
7
8
9

仔细观察可以发现一个是实例调用,一个是类调用。

# 讨论

在类中定义装饰器初看上去好像很奇怪,但是在标准库中有很多这样的例子。 特别的,@property 装饰器实际上是一个类,它里面定义了三个方法 getter(), setter(), deleter() , 每一个方法都是一个装饰器。例如:

class Person:
    # Create a property instance
    first_name = property()

    # Apply decorator methods
    @first_name.getter
    def first_name(self):
        return self._first_name

    @first_name.setter
    def first_name(self, value):
        if not isinstance(value, str):
            raise TypeError('Expected a string')
        self._first_name = value
1
2
3
4
5
6
7
8
9
10
11
12
13
14

它为什么要这么定义的主要原因是各种不同的装饰器方法会在关联的 property 实例上操作它的状态。 因此,任何时候只要你碰到需要在装饰器中记录或绑定信息,那么这不失为一种可行方法。

在类中定义装饰器有个难理解的地方就是对于额外参数 self 或 cls 的正确使用。 尽管最外层的装饰器函数比如 decorator1() 或 decorator2() 需要提供一个 self 或 cls 参数, 但是在两个装饰器内部被创建的 wrapper() 函数并不需要包含这个 self 参数。 你唯一需要这个参数是在你确实要访问包装器中这个实例的某些部分的时候。其他情况下都不用去管它。

对于类里面定义的包装器还有一点比较难理解,就是在涉及到继承的时候。 例如,假设你想让在A中定义的装饰器作用在子类B中。你需要像下面这样写:

class B(A):
    @A.decorator2
    def bar(self):
        pass
1
2
3
4

也就是说,装饰器要被定义成类方法并且你必须显式的使用父类名去调用它。 你不能使用 @B.decorator2 ,因为在方法定义时,这个类B还没有被创建。

编辑 (opens new window)
上次更新: 2023/10/13, 17:39:25
利用装饰器强制函数上的类型检查
将装饰器定义为类

← 利用装饰器强制函数上的类型检查 将装饰器定义为类→

最近更新
01
牛客网非技术快速入门SQL练习题
03-08
02
其他日常SQL题
03-07
03
用户与权限管理
03-05
更多文章>
Theme by Vdoing | Copyright © 2021-2023 | Weibw | 辽ICP备18015889号
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式