当前位置:   article > 正文

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

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

目录

一、概述

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/664302
推荐阅读
相关标签
  

闽ICP备14008679号