当前位置:   article > 正文

Python魔法之旅-魔法方法(02)_python 魔法

python 魔法

目录

一、概述

1、定义

2、作用

二、主要应用场景

1、构造和析构

2、操作符重载

3、字符串和表示

4、容器管理

5、可调用对象

6、上下文管理

7、属性访问和描述符

8、迭代器和生成器

9、数值类型

10、复制和序列化

11、自定义元类行为

12、自定义类行为

13、类型检查和转换

14、自定义异常

三、学习方法

1、理解基础

2、查阅文档

3、编写示例

4、实践应用

5、阅读他人代码

6、参加社区讨论

7、持续学习

8、练习与总结

9、注意兼容性

10、避免过度使用

四、魔法方法

6、__ceil__方法

6-1、语法

6-2、参数

6-3、功能

6-4、返回值

6-5、说明

6-6、用法

7、__complex__方法

7-1、语法

7-2、参数

7-3、功能

7-4、返回值

7-5、说明

7-6、用法

8、__contains__方法

8-1、语法

8-2、参数

8-3、功能

8-4、返回值

8-5、说明

8-6、用法

9、__delattr__方法

9-1、语法

9-2、参数

9-3、功能

9-4、返回值

9-5、说明

9-6、用法

10、__delete__方法

10-1、语法

10-2、参数

10-3、功能

10-4、返回值

10-5、说明

10-6、用法

五、推荐阅读

1、Python筑基之旅

2、Python函数之旅

3、Python算法之旅

4、博客个人主页

一、概述

1、定义

        魔法方法(Magic Methods/Special Methods,也称特殊方法或双下划线方法)是Python中一类具有特殊命名规则的方法,它们的名称通常以双下划线(`__`)开头和结尾

        魔法方法用于在特定情况下自动被Python解释器调用,而不需要显式地调用它们,它们提供了一种机制,让你可以定义自定义类时具有与内置类型相似的行为。

2、作用

        魔法方法允许开发者重载Python中的一些内置操作或函数的行为,从而为自定义的类添加特殊的功能

二、主要应用场景

1、构造和析构

1-1、__init__(self, [args...]):在创建对象时初始化属性。
1-2、__new__(cls, [args...]):在创建对象时控制实例的创建过程(通常与元类一起使用)。
1-3、__del__(self):在对象被销毁前执行清理操作,如关闭文件或释放资源。

2、操作符重载

2-1、__add__(self, other)、__sub__(self, other)、__mul__(self, other)等:自定义对象之间的算术运算。
2-2、__eq__(self, other)、__ne__(self, other)、__lt__(self, other)等:定义对象之间的比较操作。

3、字符串和表示

3-1、__str__(self):定义对象的字符串表示,常用于print()函数。
3-2、__repr__(self):定义对象的官方字符串表示,用于repr()函数和交互式解释器。

4、容器管理

4-1、__getitem__(self, key)、__setitem__(self, key, value)、__delitem__(self, key):用于实现类似列表或字典的索引访问、设置和删除操作。
4-2、__len__(self):返回对象的长度或元素个数。

5、可调用对象

5-1、__call__(self, [args...]):允许对象像函数一样被调用。

6、上下文管理

6-1、__enter__(self)、__exit__(self, exc_type, exc_val, exc_tb):用于实现上下文管理器,如with语句中的对象。

7、属性访问和描述符

7-1、__getattr__, __setattr__, __delattr__:这些方法允许对象在访问或修改不存在的属性时执行自定义操作。
7-2、描述符(Descriptors)是实现了__get__, __set__, 和__delete__方法的对象,它们可以控制对另一个对象属性的访问。

8、迭代器和生成器

8-1、__iter__和__next__:这些方法允许对象支持迭代操作,如使用for循环遍历对象。
8-2、__aiter__, __anext__:这些是异步迭代器的魔法方法,用于支持异步迭代。

9、数值类型

9-1、__int__(self)、__float__(self)、__complex__(self):定义对象到数值类型的转换。
9-2、__index__(self):定义对象用于切片时的整数转换。

10、复制和序列化

10-1、__copy__和__deepcopy__:允许对象支持浅复制和深复制操作。
10-2、__getstate__和__setstate__:用于自定义对象的序列化和反序列化过程。

11、自定义元类行为

11-1、__metaclass__(Python 2)或元类本身(Python 3):允许自定义类的创建过程,如动态创建类、修改类的定义等。

12、自定义类行为

12-1、__init__和__new__:用于初始化对象或控制对象的创建过程。
12-2、__init_subclass__:在子类被创建时调用,允许在子类中执行一些额外的操作。

13、类型检查和转换

13-1、__instancecheck__和__subclasscheck__:用于自定义isinstance()和issubclass()函数的行为。

14、自定义异常

14-1、你可以通过继承内置的Exception类来创建自定义的异常类,并定义其特定的行为。

三、学习方法

        要学好Python的魔法方法,你可以遵循以下方法及步骤:

1、理解基础

        首先确保你对Python的基本语法、数据类型、类和对象等概念有深入的理解,这些是理解魔法方法的基础。

2、查阅文档

        仔细阅读Python官方文档中关于魔法方法的部分,文档会详细解释每个魔法方法的作用、参数和返回值。你可以通过访问Python的官方网站或使用help()函数在Python解释器中查看文档。

3、编写示例

        为每个魔法方法编写简单的示例代码,以便更好地理解其用法和效果,通过实际编写和运行代码,你可以更直观地感受到魔法方法如何改变对象的行为。

4、实践应用

        在实际项目中尝试使用魔法方法。如,你可以创建一个自定义的集合类,使用__getitem__、__setitem__和__delitem__方法来实现索引操作。只有通过实践应用,你才能更深入地理解魔法方法的用途和重要性。

5、阅读他人代码

        阅读开源项目或他人编写的代码,特别是那些使用了魔法方法的代码,这可以帮助你学习如何在实际项目中使用魔法方法。通过分析他人代码中的魔法方法使用方式,你可以学习到一些新的技巧和最佳实践。

6、参加社区讨论

        参与Python社区的讨论,与其他开发者交流关于魔法方法的使用经验和技巧,在社区中提问或回答关于魔法方法的问题,这可以帮助你更深入地理解魔法方法并发现新的应用场景。

7、持续学习

        Python语言和其生态系统不断发展,新的魔法方法和功能可能会不断被引入,保持对Python社区的关注,及时学习新的魔法方法和最佳实践。

8、练习与总结

        多做练习,通过编写各种使用魔法方法的代码来巩固你的理解,定期总结你学到的知识和经验,形成自己的知识体系。

9、注意兼容性

        在使用魔法方法时,要注意不同Python版本之间的兼容性差异,确保你的代码在不同版本的Python中都能正常工作。

10、避免过度使用

        虽然魔法方法非常强大,但过度使用可能会导致代码难以理解和维护,在编写代码时,要权衡使用魔法方法的利弊,避免滥用。

        总之,学好Python的魔法方法需要不断地学习、实践和总结,只有通过不断地练习和积累经验,你才能更好地掌握这些强大的工具,并在实际项目中灵活运用它们。

四、魔法方法

6、__ceil__方法

6-1、语法
  1. __ceil__(self, /)
  2. Return the ceiling as an Integral
6-2、参数

6-2-1、self(必须)调用该方法的对象本身。

6-2-2、/(可选)这是从Python 3.8开始引入的参数注解语法,它表示这个方法不接受任何位置参数(positional-only parameters)之后的关键字参数(keyword arguments)。

6-3、功能

        用于定义对象的上限取整行为。

6-4、返回值

        返回一个不大于其调用者(即调用该方法的对象)的最小整数,即它返回调用者的上限或最小上界整数。

6-5、说明

        在大多数情况下,你不需要为你的类实现 __ceil__ 方法,除非你正在创建一个需要自定义上限行为的数值类型。

6-6、用法
  1. # 006、__ceil__方法:
  2. class CustomNumber:
  3. def __init__(self, value):
  4. self.value = float(value)
  5. def __ceil__(self):
  6. """
  7. 模拟上限取整行为
  8. """
  9. import math
  10. return math.ceil(self.value)
  11. def __repr__(self):
  12. """
  13. 提供一个友好的字符串表示
  14. """
  15. return f"CustomNumber({self.value})"
  16. # 使用示例
  17. cn = CustomNumber(3.14)
  18. # 直接调用 __ceil__ 方法(通常不推荐这样做,因为它是一个“私有”方法)
  19. print(cn.__ceil__()) # 输出: 4
  20. # 更好的做法:提供一个公共的 ceil 方法
  21. class BetterCustomNumber(CustomNumber):
  22. def ceil(self):
  23. """
  24. 提供一个公共的上限取整方法
  25. """
  26. return self.__ceil__()
  27. bcn = BetterCustomNumber(3.14)
  28. print(bcn.ceil()) # 输出: 4

7、__complex__方法

7-1、语法
  1. __complex__(self, /)
  2. Convert this value to exact type complex
7-2、参数

7-2-1、self(必须)调用该方法的对象本身。

7-2-2、/(可选)这是从Python 3.8开始引入的参数注解语法,它表示这个方法不接受任何位置参数(positional-only parameters)之后的关键字参数(keyword arguments)。

7-3、功能

        用于定义当对象被需要转换为复数类型(complex)时的行为。

7-4、返回值

        返回一个复数,或者抛出一个异常(如果无法转换为复数)。

7-5、说明

        无

7-6、用法
  1. # 007、__complex__方法:
  2. # 1、简单的复数类
  3. class SimpleComplex:
  4. def __init__(self, real, imag):
  5. self.real = real
  6. self.imag = imag
  7. def __complex__(self):
  8. return complex(self.real, self.imag)
  9. # 使用
  10. c = SimpleComplex(3, 4)
  11. print(complex(c)) # 输出: (3+4j)
  12. # 2、从字符串解析复数
  13. class ComplexFromString:
  14. def __init__(self, s):
  15. self.s = s
  16. def __complex__(self):
  17. return complex(self.s)
  18. # 使用
  19. c = ComplexFromString("3+4j")
  20. print(complex(c)) # 输出: (3+4j)
  21. # 3、极坐标到直角坐标的复数
  22. import math
  23. class PolarComplex:
  24. def __init__(self, r, theta):
  25. self.r = r
  26. self.theta = theta
  27. def __complex__(self):
  28. return complex(self.r * math.cos(self.theta), self.r * math.sin(self.theta))
  29. # 使用
  30. c = PolarComplex(5, math.pi / 4)
  31. print(complex(c)) # 输出类似: (3.5355339059327378+3.5355339059327378j)
  32. # 4、复数运算的结果
  33. class ComplexOperationResult:
  34. def __init__(self, real, imag):
  35. self.real = real
  36. self.imag = imag
  37. def __complex__(self):
  38. return complex(self.real, self.imag)
  39. # 假设这是某个复数运算的结果
  40. result = ComplexOperationResult(1, 2)
  41. print(complex(result)) # 输出: (1+2j)
  42. # 5、从列表构造复数
  43. class ComplexFromList:
  44. def __init__(self, lst):
  45. if len(lst) != 2:
  46. raise ValueError("List must contain exactly two elements")
  47. self.real, self.imag = lst
  48. def __complex__(self):
  49. return complex(self.real, self.imag)
  50. # 使用
  51. c = ComplexFromList([3, 4])
  52. print(complex(c)) # 输出: (3+4j)
  53. # 6、从字典构造复数
  54. class ComplexFromDict:
  55. def __init__(self, dct):
  56. if 'real' not in dct or 'imag' not in dct:
  57. raise ValueError("Dictionary must contain 'real' and 'imag' keys")
  58. self.real = dct['real']
  59. self.imag = dct['imag']
  60. def __complex__(self):
  61. return complex(self.real, self.imag)
  62. # 使用
  63. c = ComplexFromDict({'real': 3, 'imag': 4})
  64. print(complex(c)) # 输出: (3+4j)
  65. # 7、复数与自定义单位的结合
  66. class ComplexWithUnit:
  67. def __init__(self, real, imag, unit):
  68. self.real = real
  69. self.imag = imag
  70. self.unit = unit
  71. def __complex__(self):
  72. # 假设我们忽略单位并只返回复数值
  73. return complex(self.real, self.imag)
  74. # 使用
  75. c = ComplexWithUnit(3, 4, "V") # V for voltage
  76. print(complex(c)) # 输出: (3+4j)
  77. # 8、复数与自定义精度的结合
  78. class ComplexWithPrecision:
  79. def __init__(self, real, imag, precision):
  80. self.real = round(real, precision)
  81. self.imag = round(imag, precision)
  82. self.precision = precision
  83. def __complex__(self):
  84. # 直接使用已经四舍五入到指定精度的实部和虚部
  85. return complex(self.real, self.imag)
  86. def __repr__(self):
  87. # 提供一个友好的字符串表示形式
  88. return f"ComplexWithPrecision({self.real}, {self.imag}, precision={self.precision})"
  89. # 使用
  90. c = ComplexWithPrecision(3.14159, 2.71828, 2)
  91. print(complex(c)) # 输出类似: (3.14+2.72j),注意这里由于四舍五入可能得到2.72而不是2.71
  92. print(c) # 输出: ComplexWithPrecision(3.14, 2.72, precision=2)

8、__contains__方法

8-1、语法
  1. __contains__(self, item, /)
  2. Return item in self
8-2、参数

8-2-1、self(必须)调用该方法的对象本身。

8-2-2、item(必须):传递给in运算符的值,用于检查它是否存在于自定义对象中。

8-2-3、/(可选)这是从Python 3.8开始引入的参数注解语法,它表示这个方法不接受任何位置参数(positional-only parameters)之后的关键字参数(keyword arguments)。

8-3、功能

        用于定义当使用 in 关键字进行成员检查时对象的行为。

8-4、返回值

        返回一个布尔值(True 或 False),表示item是否存在于对象中。

8-5、说明

        在 __contains__ 方法的实现中,你应该编写逻辑来判断item是否存在于你的对象中。如果item存在,则返回True;如果item不存在,则返回False

8-6、用法
  1. # 008、__contains__方法:
  2. # 1、简单的列表类
  3. class MyList:
  4. def __init__(self, items):
  5. self.items = items
  6. def __contains__(self, item):
  7. return item in self.items
  8. # 使用
  9. my_list = MyList([1, 2, 3])
  10. print(1 in my_list) # 输出: True
  11. # 2、字典,检查键是否存在
  12. class MyDict:
  13. def __init__(self, items):
  14. self.items = items
  15. def __contains__(self, key):
  16. return key in self.items
  17. # 使用
  18. my_dict = MyDict({'a': 1, 'b': 2})
  19. print('a' in my_dict) # 输出: True
  20. # 3、字符串类,检查子串
  21. class MyString:
  22. def __init__(self, s):
  23. self.s = s
  24. def __contains__(self, substring):
  25. return substring in self.s
  26. # 使用
  27. my_string = MyString('hello, world')
  28. print('world' in my_string) # 输出: True
  29. # 4、自定义集合类
  30. class MySet:
  31. def __init__(self, items):
  32. self.items = set(items)
  33. def __contains__(self, item):
  34. return item in self.items
  35. # 使用
  36. my_set = MySet({1, 2, 3})
  37. print(2 in my_set) # 输出: True
  38. # 5、区间类,检查数值是否在区间内
  39. class Interval:
  40. def __init__(self, start, end):
  41. self.start = start
  42. self.end = end
  43. def __contains__(self, value):
  44. return self.start <= value <= self.end
  45. # 使用
  46. interval = Interval(1, 5)
  47. print(3 in interval) # 输出: True
  48. # 6、自定义树形结构,检查节点是否存在
  49. class TreeNode:
  50. def __init__(self, value):
  51. self.value = value
  52. self.children = []
  53. def add_child(self, node):
  54. self.children.append(node)
  55. def __contains__(self, value):
  56. if self.value == value:
  57. return True
  58. for child in self.children:
  59. if value in child:
  60. return True
  61. return False
  62. # 使用
  63. root = TreeNode(1)
  64. child1 = TreeNode(2)
  65. root.add_child(child1)
  66. print(2 in root) # 输出: True
  67. # 7、检查文件名的后缀
  68. class File:
  69. def __init__(self, filename):
  70. self.filename = filename
  71. def __contains__(self, suffix):
  72. return self.filename.endswith(suffix)
  73. # 使用
  74. file = File('example.txt')
  75. print('.txt' in file) # 输出: True
  76. # 8、检查字符串是否包含大写字母
  77. class StringChecker:
  78. def __init__(self, s):
  79. self.s = s
  80. def __contains__(self, char_type):
  81. if char_type == 'uppercase':
  82. return any(c.isupper() for c in self.s)
  83. else:
  84. raise ValueError("Unknown char_type")
  85. # 使用
  86. checker = StringChecker('Hello, World!')
  87. print('uppercase' in checker) # 输出: True
  88. # 9、自定义数字范围类,支持步长
  89. class Range:
  90. def __init__(self, start, end, step=1):
  91. self.start = start
  92. self.end = end
  93. self.step = step
  94. # 确保步长不为0,并且如果end小于start,步长应该为负数
  95. if self.step == 0:
  96. raise ValueError("Step cannot be zero")
  97. if (self.end < self.start and self.step > 0) or (self.end > self.start and self.step < 0):
  98. raise ValueError("Invalid range with given step")
  99. def __contains__(self, value):
  100. # 确保value在范围内
  101. if self.step > 0 and (value < self.start or value > self.end):
  102. return False
  103. if self.step < 0 and (value > self.start or value < self.end):
  104. return False
  105. # 检查value是否是范围内的某个步长点
  106. if (value - self.start) % self.step == 0:
  107. return True
  108. return False
  109. # 使用示例
  110. my_range = Range(1, 10, 2) # 创建一个范围从1到10,步长为2的Range对象
  111. print(3 in my_range) # 输出: True,因为3是范围内的步长点(1, 3, 5, ..., 9)
  112. print(4 in my_range) # 输出: False,因为4不是步长为2的Range对象中的点
  113. print(11 in my_range) # 输出: False,因为11超出了范围
  114. my_range_negative = Range(10, 1, -2) # 创建一个从10到1,步长为-2的Range对象
  115. print(8 in my_range_negative) # 输出: True,因为8是范围内的步长点(10, 8, 6, 4, 2)

9、__delattr__方法

9-1、语法
  1. __delattr__(self, name, /)
  2. Implement delattr(self, name)
9-2、参数

9-2-1、self(必须)调用该方法的对象本身。

9-2-2、name(必须):表示要被删除的属性名。

9-2-3、/(可选)这是从Python 3.8开始引入的参数注解语法,它表示这个方法不接受任何位置参数(positional-only parameters)之后的关键字参数(keyword arguments)。

9-3、功能

        用于定义当尝试删除对象的属性时发生的操作。

9-4、返回值

        无

9-5、说明

        当你使用del语句删除一个对象的属性时,该操作是一个表达式语句(expression statement),而不是一个表达式(expression),因此,它本身不产生任何值(即没有返回值)。

9-6、用法
  1. # 009、__delattr__方法:
  2. # 1、禁止删除特定属性
  3. class ProhibitedDeletion:
  4. def __init__(self):
  5. self.protected_attr = "This cannot be deleted"
  6. def __delattr__(self, name):
  7. if name == "protected_attr":
  8. raise AttributeError("Cannot delete protected_attr")
  9. else:
  10. super().__delattr__(name)
  11. # 2、记录属性删除
  12. class DeletionLogger:
  13. def __init__(self):
  14. self.log = []
  15. def __delattr__(self, name):
  16. self.log.append(f"Deleting attribute: {name}")
  17. super().__delattr__(name)
  18. # 3、删除前验证
  19. class ValidatedDeletion:
  20. def __init__(self):
  21. self.valid_attr = True
  22. def __delattr__(self, name):
  23. if name == "valid_attr" and not getattr(self, name, False):
  24. raise ValueError("Cannot delete invalid attribute")
  25. super().__delattr__(name)
  26. # 4、触发清理函数
  27. class CleanupOnDeletion:
  28. def __init__(self):
  29. self.resource = "Some resource"
  30. def cleanup(self):
  31. print("Cleaning up resource")
  32. def __delattr__(self, name):
  33. if name == "resource":
  34. self.cleanup()
  35. super().__delattr__(name)
  36. # 5、删除前检查类型
  37. class TypedDeletion:
  38. def __init__(self):
  39. self.int_attr = 10
  40. def __delattr__(self, name):
  41. if name == "int_attr" and not isinstance(getattr(self, name, None), int):
  42. raise TypeError("int_attr must be an integer to delete")
  43. super().__delattr__(name)
  44. # 6、替换为默认值
  45. class DefaultOnDeletion:
  46. def __init__(self):
  47. self.replaceable_attr = "Initial value"
  48. def __delattr__(self, name):
  49. if name == "replaceable_attr":
  50. setattr(self, name, "Default value")
  51. else:
  52. super().__delattr__(name)
  53. # 7、延迟删除
  54. class DelayedDeletion:
  55. def __init__(self):
  56. self.delayed_attr = "Delayed deletion"
  57. self.deletion_scheduled = False
  58. def __delattr__(self, name):
  59. if name == "delayed_attr":
  60. self.deletion_scheduled = True
  61. print("Deletion of delayed_attr is scheduled")
  62. else:
  63. super().__delattr__(name)
  64. def perform_deletions(self):
  65. if self.deletion_scheduled:
  66. del self.delayed_attr
  67. self.deletion_scheduled = False
  68. # 8、递归删除(递归删除需要小心处理,以避免无限递归或栈溢出)
  69. class RecursiveDeletion:
  70. def __init__(self):
  71. self.nested = RecursiveDeletion()
  72. def __delattr__(self, name):
  73. if name == "nested" and isinstance(getattr(self, name, None), RecursiveDeletion):
  74. print("Recursively deleting nested object")
  75. delattr(getattr(self, name), "nested") # 假设嵌套对象也有相同的结构
  76. super().__delattr__(name)
  77. # 9、属性删除后的回调
  78. class CallbackOnDeletion:
  79. def __init__(self):
  80. self.attr = "To be deleted"
  81. self.callbacks = []
  82. def register_callback(self, callback):
  83. self.callbacks.append(callback)
  84. def __delattr__(self, name):
  85. if name == "attr":
  86. for callback in self.callbacks:
  87. callback()
  88. super().__delattr__(name)
  89. # 10、属性删除通知
  90. class NotifyingClass:
  91. def __init__(self):
  92. self.some_attr = "This attribute can be deleted"
  93. def __delattr__(self, name):
  94. if hasattr(self, name): # 确保属性确实存在
  95. print(f"Attribute '{name}' is being deleted.")
  96. super().__delattr__(name) # 调用父类的__delattr__方法来实际删除属性
  97. else:
  98. print(f"Attribute '{name}' does not exist.")
  99. # 使用示例
  100. obj = NotifyingClass()
  101. print(obj.some_attr) # 输出: This attribute can be deleted
  102. del obj.some_attr # 输出: Attribute 'some_attr' is being deleted.
  103. # 尝试删除不存在的属性
  104. del obj.non_existent # 输出: Attribute 'non_existent' does not exist.

10、__delete__方法

10-1、语法
  1. __delete__(self, instance, /)
  2. Delete an attribute of instance
10-2、参数

10-2-1、self(必须)描述符类的实例(即描述符对象自身)。

10-2-2、instance(必须):拥有描述符属性的实例。

10-2-3、/(可选)这是从Python 3.8开始引入的参数注解语法,它表示这个方法不接受任何位置参数(positional-only parameters)之后的关键字参数(keyword arguments)。

10-3、功能

        用于处理在拥有者(owner)类或其实例上删除描述符属性时的行为。

10-4、返回值

        该方法并不返回一个值,或者说它的返回值是None。

10-5、说明

        当从拥有者实例上删除描述符属性时,这个实例会作为instance参数传入;如果在类级别(而不是实例级别)删除描述符,则instance参数会被设置为None(因为类本身没有实例)。

        虽然__delete__方法允许你控制删除操作,但它并不能真正地从内存中删除描述符对象本身。

10-6、用法
  1. # 010、__delete__方法:
  2. # 1、基本用法
  3. class Descriptor:
  4. def __delete__(self, instance):
  5. print(f"Deleting descriptor for instance {instance}")
  6. class MyClass:
  7. attr = Descriptor()
  8. obj = MyClass()
  9. del obj.attr # 输出: Deleting descriptor for instance <__main__.MyClass object at 0x000001E97E39F7D0>
  10. # 2、带有状态清理
  11. class Resource:
  12. def __init__(self):
  13. self.is_open = True
  14. def close(self):
  15. self.is_open = False
  16. class DescriptorWithCleanup:
  17. def __init__(self):
  18. self.resource = Resource()
  19. def __delete__(self, instance):
  20. if self.resource.is_open:
  21. self.resource.close()
  22. print("Resource closed")
  23. class MyClass:
  24. attr = DescriptorWithCleanup()
  25. obj = MyClass()
  26. del obj.attr # 输出: Resource closed
  27. # 3、检查实例
  28. class Descriptor:
  29. def __delete__(self, instance):
  30. if instance is None:
  31. print("Deleting at class level is not allowed")
  32. else:
  33. print(f"Deleting descriptor for instance {instance}")
  34. class MyClass:
  35. attr = Descriptor()
  36. # del MyClass.attr # 这会触发 "Deleting at class level is not allowed"
  37. obj = MyClass()
  38. del obj.attr # 输出: Deleting descriptor for instance <__main__.MyClass object at 0x000001845CC61150>
  39. # 4、记录删除操作
  40. class LoggingDescriptor:
  41. def __delete__(self, instance):
  42. with open("log.txt", "a") as file:
  43. file.write(f"Deleting descriptor for instance {instance}\n")
  44. # 5、抛出异常
  45. class ProtectedDescriptor:
  46. def __delete__(self, instance):
  47. raise AttributeError("This descriptor cannot be deleted")
  48. del obj.attr # 这会触发 AttributeError: This descriptor cannot be deleted
  49. # 6、使用weakref
  50. import weakref
  51. class WeakRefDescriptor:
  52. def __init__(self):
  53. self._refs = weakref.WeakSet()
  54. def __get__(self, instance, owner):
  55. if instance is not None:
  56. self._refs.add(instance)
  57. return instance
  58. def __delete__(self, instance):
  59. if instance is not None:
  60. self._refs.discard(instance)
  61. print(f"Instance {instance} removed from weak references")

五、推荐阅读

1、Python筑基之旅

2、Python函数之旅

3、Python算法之旅

4、博客个人主页

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/你好赵伟/article/detail/756635
推荐阅读
相关标签
  

闽ICP备14008679号