当前位置:   article > 正文

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

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

目录

一、概述

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、避免过度使用

四、魔法方法

20、__format__方法

20-1、语法

20-2、参数

20-3、功能

20-4、返回值

20-5、说明

20-6、用法

21、__ge__方法

21-1、语法

21-2、参数

21-3、功能

21-4、返回值

21-5、说明

21-6、用法

22、__get__方法

22-1、语法

22-2、参数

22-3、功能

22-4、返回值

22-5、说明

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

四、魔法方法

20、__format__方法

20-1、语法
  1. __format__(self, format_spec, /)
  2. Default object formatter
20-2、参数

20-2-1、self(必须)一个对实例对象本身的引用,在类的所有方法中都会自动传递。 

20-2-2、format_spec(必须)一个字符串,表示格式说明符。它定义了应该如何格式化对象。

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

20-3、功能

        用于定义对象的自定义格式化字符串表示。

20-4、返回值

        返回一个字符串,该字符串表示按照format_spec格式化后的对象。

20-5、说明

        在定义__format__方法时,你可以根据需要实现复杂的格式化逻辑。例如,你可以检查 format_spec 的值,并根据不同的值返回不同的字符串表示。

20-6、用法
  1. # 020、__format__方法:
  2. # 1、简单的整数格式化
  3. class MyInt:
  4. def __init__(self, value):
  5. self.value = value
  6. def __format__(self, format_spec):
  7. return format(self.value, format_spec)
  8. if __name__ == '__main__':
  9. num = MyInt(12345)
  10. print(format(num, '08d')) # 输出: 00012345
  11. # 2、自定义日期格式化
  12. from datetime import datetime
  13. class MyDate:
  14. def __init__(self, year, month, day):
  15. self.date = datetime(year, month, day)
  16. def __format__(self, format_spec):
  17. return self.date.strftime(format_spec)
  18. if __name__ == '__main__':
  19. date = MyDate(2023, 3, 17)
  20. print(format(date, '%Y-%m-%d')) # 输出: 2023-03-17
  21. # 3、货币格式化
  22. class Money:
  23. def __init__(self, amount):
  24. self.amount = amount
  25. def __format__(self, format_spec):
  26. if format_spec == 'c':
  27. return f'${self.amount:.2f}'.replace('.', ',')
  28. else:
  29. return format(self.amount, format_spec)
  30. if __name__ == '__main__':
  31. money = Money(12345.6789)
  32. print(format(money, 'c')) # 输出: $12,345.68
  33. # 4、百分比格式化
  34. class Percentage:
  35. def __init__(self, value):
  36. self.value = value
  37. def __format__(self, format_spec):
  38. return format(self.value * 100, format_spec) + '%'
  39. if __name__ == '__main__':
  40. percentage = Percentage(0.85)
  41. print(format(percentage, '.1f')) # 输出: 85.0%
  42. # 5、分数格式化(带分数和小数)
  43. from fractions import Fraction
  44. class MixedNumber:
  45. def __init__(self, numerator, denominator):
  46. self.fraction = Fraction(numerator, denominator)
  47. def __format__(self, format_spec):
  48. whole, numerator = divmod(self.fraction.numerator, self.fraction.denominator)
  49. return f'{whole} {numerator}/{self.fraction.denominator}'
  50. if __name__ == '__main__':
  51. mixed = MixedNumber(7, 3)
  52. print(format(mixed, '')) # 输出: 2 1/3
  53. # 6、十六进制颜色格式化
  54. class Color:
  55. def __init__(self, r, g, b):
  56. self.rgb = (r, g, b)
  57. def __format__(self, format_spec):
  58. if format_spec == 'hex':
  59. return "#{:02x}{:02x}{:02x}".format(self.rgb[0], self.rgb[1], self.rgb[2])
  60. else:
  61. raise ValueError("Invalid format specifier for Color")
  62. if __name__ == '__main__':
  63. color = Color(255, 0, 0)
  64. print(format(color, 'hex')) # 输出: #ff0000
  65. # 7、自定义二进制表示
  66. class Binary:
  67. def __init__(self, value):
  68. self.value = value
  69. def __format__(self, format_spec):
  70. if format_spec == 'b':
  71. return bin(self.value)[2:] # 去掉'0b'前缀
  72. else:
  73. return format(self.value, format_spec)
  74. if __name__ == '__main__':
  75. binary = Binary(10)
  76. print(format(binary, 'b')) # 输出: 1010
  77. # 8、自定义角度格式化(转为度分秒)
  78. class Angle:
  79. def __init__(self, degrees):
  80. self.degrees = degrees
  81. def __format__(self, format_spec):
  82. if format_spec == 'dms':
  83. # 将角度转换为度分秒
  84. minutes, seconds = divmod(abs(self.degrees) * 60, 60)
  85. degrees = int(abs(self.degrees))
  86. seconds = round(seconds, 2) # 保留两位小数
  87. degrees_sign = '' if self.degrees >= 0 else '-'
  88. # 格式化输出
  89. return f"{degrees_sign}{degrees:02d}°{int(minutes):02d}{seconds:05.2f}″"
  90. else:
  91. raise ValueError(f"Invalid format specifier for Angle: '{format_spec}'")
  92. if __name__ == '__main__':
  93. angle = Angle(123.4567)
  94. print(format(angle, 'dms')) # 输出: 123°123′27.40″
  95. angle_negative = Angle(-45.1234)
  96. print(format(angle_negative, 'dms')) # 输出: -45°45′07.40″
  97. # 9、自定义时间格式化
  98. from datetime import timedelta
  99. class CustomTimeDelta:
  100. def __init__(self, seconds):
  101. self.seconds = seconds
  102. def __format__(self, format_spec):
  103. if format_spec == 'hms':
  104. hours, remainder = divmod(self.seconds, 3600)
  105. minutes, seconds = divmod(remainder, 60)
  106. return f"{int(hours):02d}:{int(minutes):02d}:{int(seconds):02d}"
  107. else:
  108. raise ValueError("Invalid format specifier for CustomTimeDelta")
  109. if __name__ == '__main__':
  110. delta = CustomTimeDelta(3725)
  111. print(format(delta, 'hms')) # 输出: 01:02:05
  112. # 10、自定义复数格式化
  113. class ComplexNumber:
  114. def __init__(self, real, imag):
  115. self.real = real
  116. self.imag = imag
  117. def __format__(self, format_spec):
  118. if format_spec == 'polar':
  119. magnitude = (self.real**2 + self.imag**2)**0.5
  120. angle = (math.atan2(self.imag, self.real) * 180 / math.pi) % 360
  121. return f"({magnitude:.2f}, {angle:.2f}°)"
  122. else:
  123. return f"{self.real:.2f} + {self.imag:.2f}j"
  124. import math
  125. if __name__ == '__main__':
  126. cn = ComplexNumber(3, 4)
  127. print(format(cn, '')) # 输出: 3.00 + 4.00j
  128. print(format(cn, 'polar')) # 输出: (5.00, 53.13°)
  129. # 11、自定义科学计数法格式化
  130. class ScientificNumber:
  131. def __init__(self, value):
  132. self.value = value
  133. def __format__(self, format_spec):
  134. if format_spec == 'sci':
  135. return f"{self.value:.2E}"
  136. else:
  137. return format(self.value, format_spec)
  138. if __name__ == '__main__':
  139. sn = ScientificNumber(123456789)
  140. print(format(sn, 'sci')) # 输出: 1.23E+08
  141. # 12、自定义二进制浮点数格式化
  142. class BinaryFloat:
  143. def __init__(self, value):
  144. self.value = value
  145. def __format__(self, format_spec):
  146. if format_spec == 'binf':
  147. # 这里为了简化,只展示整数部分和小数点后一位的二进制表示
  148. integer_part = bin(int(self.value))[2:]
  149. fraction_part = bin(int((self.value - int(self.value)) * 2))[2:3]
  150. return f"{integer_part}.{fraction_part}"
  151. else:
  152. return format(self.value, format_spec)
  153. if __name__ == '__main__':
  154. bf = BinaryFloat(3.5)
  155. print(format(bf, 'binf')) # 输出可能不完全准确,因为浮点数二进制表示有限: 11.1

21、__ge__方法

21-1、语法
  1. __ge__(self, other, /)
  2. Return self >= other
21-2、参数

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

21-2-2、other(必须)表示要与self进行比较的另一个对象,它可以是与self相同类型的对象,也可以是其他类型的对象(这取决于你的比较逻辑)。

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

21-3、功能

        用于实现对象的“大于或等于”比较操作。

21-4、返回值

        返回一个布尔值(True或False),指示self是否大于或等于other。

21-5、说明

        无

21-6、用法
  1. # 021、__ge__方法:
  2. # 1、整数类
  3. class IntWrapper:
  4. def __init__(self, value):
  5. self.value = value
  6. def __ge__(self, other):
  7. if isinstance(other, IntWrapper):
  8. return self.value >= other.value
  9. elif isinstance(other, int):
  10. return self.value >= other
  11. else:
  12. return NotImplemented
  13. if __name__ == '__main__':
  14. a = IntWrapper(5)
  15. b = IntWrapper(3)
  16. print(a >= b) # True
  17. print(a >= 4) # True
  18. print(a >= IntWrapper(6)) # False
  19. # 2、字符串长度比较
  20. class StringLength:
  21. def __init__(self, string):
  22. self.string = string
  23. def __ge__(self, other):
  24. if isinstance(other, StringLength):
  25. return len(self.string) >= len(other.string)
  26. elif isinstance(other, int):
  27. return len(self.string) >= other
  28. else:
  29. return NotImplemented
  30. if __name__ == '__main__':
  31. s1 = StringLength("hello")
  32. s2 = StringLength("Myelsa")
  33. print(s1 >= s2) # False
  34. print(s1 >= 4) # True
  35. # 3、自定义分数类
  36. from fractions import Fraction
  37. class MyFraction:
  38. def __init__(self, numerator, denominator):
  39. self.fraction = Fraction(numerator, denominator)
  40. def __ge__(self, other):
  41. if isinstance(other, MyFraction):
  42. return self.fraction >= other.fraction
  43. elif isinstance(other, (int, float)):
  44. return self.fraction >= Fraction(other)
  45. else:
  46. return NotImplemented
  47. if __name__ == '__main__':
  48. f1 = MyFraction(1, 2)
  49. f2 = MyFraction(3, 4)
  50. print(f1 >= f2) # False
  51. print(f1 >= 0.4) # True
  52. # 4、自定义点类(二维空间)
  53. class Point:
  54. def __init__(self, x, y):
  55. self.x = x
  56. self.y = y
  57. def __ge__(self, other):
  58. if isinstance(other, Point):
  59. return self.x >= other.x and self.y >= other.y
  60. else:
  61. return NotImplemented
  62. if __name__ == '__main__':
  63. p1 = Point(3, 6)
  64. p2 = Point(10, 8)
  65. print(p1 >= p2) # False
  66. # 5、自定义字典长度比较
  67. class DictLengthWrapper:
  68. def __init__(self, dictionary):
  69. self.dictionary = dictionary
  70. def __ge__(self, other):
  71. if isinstance(other, DictLengthWrapper):
  72. return len(self.dictionary) >= len(other.dictionary)
  73. elif isinstance(other, int):
  74. return len(self.dictionary) >= other
  75. else:
  76. return NotImplemented
  77. if __name__ == '__main__':
  78. d1 = DictLengthWrapper({'a': 1, 'b': 2})
  79. d2 = DictLengthWrapper({'c': 3})
  80. print(d1 >= d2) # True
  81. print(d1 >= 2) # True
  82. # 6、自定义时间类
  83. class CustomDate:
  84. def __init__(self, year, month, day):
  85. self.year = year
  86. self.month = month
  87. self.day = day
  88. def __repr__(self):
  89. return f"CustomDate({self.year}, {self.month}, {self.day})"
  90. def __str__(self):
  91. return f"{self.year}-{self.month}-{self.day}"
  92. def __ge__(self, other):
  93. if isinstance(other, CustomDate):
  94. # 比较年份,年份大的日期大
  95. if self.year > other.year:
  96. return True
  97. # 如果年份相同,比较月份
  98. elif self.year == other.year and self.month > other.month:
  99. return True
  100. # 如果年份和月份都相同,比较天数
  101. elif self.year == other.year and self.month == other.month and self.day >= other.day:
  102. return True
  103. # 其他情况,当前日期小于或等于比较日期
  104. else:
  105. return False
  106. else:
  107. # 对于非CustomDate类型的比较,返回NotImplemented
  108. return NotImplemented
  109. if __name__ == '__main__':
  110. d1 = CustomDate(2009, 10, 8)
  111. d2 = CustomDate(2018, 3, 6)
  112. d3 = CustomDate(2024, 3, 13)
  113. print(d1 >= d2) # False
  114. print(d1 >= d3) # False
  115. print(d2 >= d3) # False
  116. # 尝试与其他类型比较,将会返回NotImplemented
  117. # print(d1 >= (2023, 3, 15)) # TypeError: '>=' not supported between instances of 'CustomDate' and 'tuple'
  118. # 7、自定义价格类
  119. class Price:
  120. def __init__(self, amount):
  121. self.amount = amount
  122. def __ge__(self, other):
  123. if isinstance(other, Price):
  124. return self.amount >= other.amount
  125. elif isinstance(other, (int, float)):
  126. return self.amount >= other
  127. else:
  128. return NotImplemented
  129. if __name__ == '__main__':
  130. p1 = Price(10.24)
  131. p2 = Price(10.18)
  132. print(p1 >= p2) # True
  133. print(p1 >= 10) # True
  134. # 8、自定义成绩类
  135. class Grade:
  136. def __init__(self, score):
  137. self.score = score
  138. def __ge__(self, other):
  139. if isinstance(other, Grade):
  140. return self.score >= other.score
  141. elif isinstance(other, (int, float)):
  142. return self.score >= other
  143. else:
  144. return NotImplemented
  145. def __str__(self):
  146. return f"Grade: {self.score}"
  147. if __name__ == '__main__':
  148. g1 = Grade(85)
  149. g2 = Grade(80)
  150. print(g1 >= g2) # True
  151. print(g1 >= 85) # True
  152. # 9、自定义长度单位类
  153. class Length:
  154. def __init__(self, meters):
  155. self.meters = meters
  156. def __ge__(self, other):
  157. if isinstance(other, Length):
  158. return self.meters >= other.meters
  159. elif isinstance(other, (int, float)):
  160. return self.meters >= other
  161. else:
  162. return NotImplemented
  163. def __str__(self):
  164. return f"{self.meters} meters"
  165. if __name__ == '__main__':
  166. l1 = Length(10)
  167. l2 = Length(5)
  168. print(l1 >= l2) # True
  169. print(l1 >= 8) # True
  170. # 10、自定义权重类(考虑精度)
  171. from decimal import Decimal, getcontext
  172. class Weight:
  173. def __init__(self, value, precision=2):
  174. getcontext().prec = precision + 2 # 设置精度以支持比较
  175. self.value = Decimal(value)
  176. def __ge__(self, other):
  177. if isinstance(other, Weight):
  178. return self.value >= other.value
  179. elif isinstance(other, (int, float, Decimal)):
  180. return self.value >= Decimal(other)
  181. else:
  182. return NotImplemented
  183. def __str__(self):
  184. return f"{self.value:.{getcontext().prec - 2}f} kg"
  185. if __name__ == '__main__':
  186. w1 = Weight('10.24')
  187. w2 = Weight('10.18')
  188. print(w1 >= w2) # True
  189. print(w1 >= 10.5) # False
  190. # 11、自定义日期类
  191. from datetime import datetime
  192. class CustomDate:
  193. def __init__(self, year, month, day):
  194. self.date = datetime(year, month, day)
  195. def __ge__(self, other):
  196. if isinstance(other, CustomDate):
  197. return self.date >= other.date
  198. elif isinstance(other, datetime):
  199. return self.date >= other
  200. else:
  201. return NotImplemented
  202. def __str__(self):
  203. return self.date.strftime('%Y-%m-%d')
  204. if __name__ == '__main__':
  205. d1 = CustomDate(2024, 3, 13)
  206. d2 = CustomDate(2024, 5, 11)
  207. print(d1 >= d2) # False
  208. print(d1 >= datetime(2023, 3, 15)) # True
  209. # 12、自定义版本类
  210. class Version:
  211. def __init__(self, version_string):
  212. self.parts = tuple(map(int, version_string.split('.')))
  213. def __ge__(self, other):
  214. if isinstance(other, Version):
  215. return self.parts >= other.parts
  216. elif isinstance(other, str):
  217. other_version = Version(other)
  218. return self.parts >= other_version.parts
  219. else:
  220. return NotImplemented
  221. def __str__(self):
  222. return '.'.join(map(str, self.parts))
  223. if __name__ == '__main__':
  224. v1 = Version('1.2.3')
  225. v2 = Version('1.2.2')
  226. print(v1 >= v2) # True
  227. print(v1 >= '1.2.3') # True

22、__get__方法

22-1、语法
  1. __get__(self, instance, owner=None, /)
  2. Return an attribute of instance, which is of type owner
22-2、参数

22-2-1、self(必须)一个对描述符实例对象本身的引用,在类的所有方法中都会自动传递。

22-2-2、instance(必须)拥有描述符的类的实例。当描述符是通过实例访问时,这个参数会被设置为实例本身;如果描述符是通过类而不是实例访问的(例如类属性),这个参数会是None。

22-2-3、owner(可选)拥有描述符的类。

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

22-3、功能

        用于访问描述符的值。

22-4、返回值

        返回一个值,即描述符被访问时应该返回的值。

22-5、说明

        在Python中,__get__ 方法通常与描述符(descriptors)一起使用,描述符是一种具有绑定行为的对象属性,这些属性可以重写属性的访问、赋值和删除操作描述符常用于实现如属性验证、类型检查、属性访问控制等高级功能。

22-6、用法
  1. # 022、__get__方法:
  2. # 1、简单的属性访问
  3. class MyDescriptor:
  4. def __init__(self, initial_value):
  5. self.value = initial_value
  6. def __get__(self, instance, owner):
  7. return self.value
  8. class MyClass:
  9. x = MyDescriptor(10)
  10. if __name__ == '__main__':
  11. obj = MyClass()
  12. print(obj.x) # 输出: 10
  13. # 2、访问实例属性(如果存在)
  14. class MyDescriptor:
  15. def __init__(self, name):
  16. self.name = name
  17. def __get__(self, instance, owner):
  18. if instance is not None and hasattr(instance, self.name):
  19. return instance.__dict__[self.name]
  20. return None
  21. class MyClass:
  22. def __init__(self, value):
  23. self.x = value
  24. x = MyDescriptor('x')
  25. if __name__ == '__main__':
  26. obj = MyClass(20)
  27. print(obj.x) # 输出: 20
  28. # 3、属性计算
  29. class MyDescriptor:
  30. def __get__(self, instance, owner):
  31. if instance is None:
  32. return self
  33. return instance.y * 2
  34. class MyClass:
  35. z = MyDescriptor()
  36. def __init__(self, y):
  37. self.y = y
  38. if __name__ == '__main__':
  39. obj = MyClass(5)
  40. print(obj.z) # 输出: 10
  41. # 4、访问控制(只读)
  42. class MyDescriptor:
  43. def __init__(self, value):
  44. self._value = value
  45. def __get__(self, instance, owner):
  46. return self._value
  47. def __set__(self, instance, value):
  48. raise AttributeError("This attribute is read-only")
  49. class MyClass:
  50. x = MyDescriptor(10)
  51. if __name__ == '__main__':
  52. obj = MyClass()
  53. print(obj.x) # 输出: 10
  54. # obj.x = 20 # 这会抛出一个AttributeError: This attribute is read-only
  55. # 5、延迟初始化
  56. class MyDescriptor:
  57. def __get__(self, instance, owner):
  58. if not hasattr(instance, '_initialized'):
  59. print('Initializing...')
  60. instance._initialized = True
  61. instance.y = 42
  62. return instance.y
  63. class MyClass:
  64. y = MyDescriptor()
  65. if __name__ == '__main__':
  66. obj = MyClass()
  67. print(obj.y) # 输出: Initializing... 42
  68. # 6、线程安全属性(简化版)
  69. import threading
  70. class ThreadSafeDescriptor:
  71. def __init__(self, init_value):
  72. self._lock = threading.Lock()
  73. self._value = init_value
  74. def __get__(self, instance, owner):
  75. with self._lock:
  76. return self._value
  77. def __set__(self, instance, value):
  78. with self._lock:
  79. self._value = value
  80. # 省略了 __set__ 的实际使用,因为它在这个简化的例子中并不明显
  81. # 7、验证属性值
  82. class MyDescriptor:
  83. def __init__(self):
  84. self._value = None
  85. def __get__(self, instance, owner):
  86. return self._value
  87. def __set__(self, instance, value):
  88. if not isinstance(value, int) or value < 0:
  89. raise ValueError("Value must be a non-negative integer")
  90. self._value = value
  91. class MyClass:
  92. x = MyDescriptor()
  93. if __name__ == '__main__':
  94. obj = MyClass()
  95. obj.x = 10 # 正常
  96. # obj.x = -1 # 这会抛出一个 ValueError
  97. # 8、缓存属性值
  98. class CachedDescriptor:
  99. def __init__(self, func):
  100. self.func = func
  101. self.name = func.__name__
  102. def __get__(self, instance, owner):
  103. if instance is None:
  104. return self
  105. # 尝试从实例的缓存中获取值
  106. cache = getattr(instance, '__cache__', None)
  107. if cache is None:
  108. cache = {}
  109. setattr(instance, '__cache__', cache)
  110. if self.name not in cache:
  111. # 如果缓存中没有值,则调用函数并存储结果
  112. cache[self.name] = self.func(instance)
  113. return cache[self.name]
  114. class MyClass:
  115. def __init__(self, data):
  116. self.data = data
  117. @CachedDescriptor
  118. def expensive_calculation(self):
  119. print("Calculating...")
  120. # 假设这是一个非常耗时的计算
  121. result = sum(range(self.data))
  122. return result
  123. if __name__ == '__main__':
  124. obj = MyClass(1000)
  125. print(obj.expensive_calculation) # 输出: Calculating... 和计算结果
  126. print(obj.expensive_calculation) # 直接从缓存中获取,不会再次计算
  127. # 9、属性依赖其他属性
  128. class DependentDescriptor:
  129. def __init__(self, attr_name):
  130. self.attr_name = attr_name
  131. def __get__(self, instance, owner):
  132. if instance is None:
  133. return self
  134. # 假设另一个属性是 instance.base_value
  135. base_value = getattr(instance, 'base_value', None)
  136. if base_value is not None:
  137. return base_value * 2 # 假设这个描述符的值是 base_value 的两倍
  138. return None
  139. class MyClass:
  140. double_value = DependentDescriptor('base_value')
  141. def __init__(self, base_value):
  142. self.base_value = base_value
  143. if __name__ == '__main__':
  144. obj = MyClass(5)
  145. print(obj.double_value) # 输出: 10

五、推荐阅读

1、Python筑基之旅

2、Python函数之旅

3、Python算法之旅

4、博客个人主页

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

闽ICP备14008679号