• Python魔法之旅-魔法方法(14)


    目录

    一、概述

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

    四、魔法方法

    44、__length_hint__方法

    44-1、语法

    44-2、参数

    44-3、功能

    44-4、返回值

    44-5、说明

    44-6、用法

    45、__lshift__方法

    45-1、语法

    45-2、参数

    45-3、功能

    45-4、返回值

    45-5、说明

    45-6、用法

    46、__lt__方法

    46-1、语法

    46-2、参数

    46-3、功能

    46-4、返回值

    46-5、说明

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

    四、魔法方法

    44、__length_hint__方法

    44-1、语法
    1. __length_hint__(self, /)
    2. Private method returning an estimate of len(list(it))
    44-2、参数

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

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

    44-3、功能

            为那些需要知道迭代器大致长度的函数或方法提供一个长度提示。

    44-4、返回值

            返回一个整数或None。

    44-5、说明

       __length_hint__方法应该返回一个整数或None

    44-5-1、如果返回整数,它应该是一个对迭代器长度的合理估计,这个估计可能并不总是准确的,但它应该尽可能接近实际长度。

    44-5-2、如果迭代器长度未知或无法合理估计,则应返回None

    44-6、用法
    1. # 044、__length_hint__方法:
    2. # 1、简单的列表包装器
    3. class MyListWrapper:
    4. def __init__(self, lst):
    5. self.lst = lst
    6. def __length_hint__(self):
    7. return len(self.lst)
    8. # 2、迭代器长度提示
    9. class MyIterator:
    10. def __init__(self, numbers):
    11. self.numbers = numbers
    12. self.index = 0
    13. def __iter__(self):
    14. return self
    15. def __next__(self):
    16. if self.index < len(self.numbers):
    17. result = self.numbers[self.index]
    18. self.index += 1
    19. return result
    20. raise StopIteration
    21. def __length_hint__(self):
    22. return len(self.numbers) - self.index
    23. # 3、动态生成的序列
    24. class DynamicSequence:
    25. def __init__(self, start, end):
    26. self.start = start
    27. self.end = end
    28. def __iter__(self):
    29. return self
    30. def __next__(self):
    31. if self.start > self.end:
    32. raise StopIteration
    33. current = self.start
    34. self.start += 1
    35. return current
    36. def __length_hint__(self):
    37. return self.end - self.start + 1 if self.start <= self.end else 0
    38. # 4、缓存长度的迭代器
    39. class CachedLengthIterator:
    40. def __init__(self, iterable):
    41. self.iterable = iterable
    42. self._length = None
    43. def __iter__(self):
    44. return iter(self.iterable)
    45. def __length_hint__(self):
    46. if self._length is None:
    47. self._length = sum(1 for _ in self.iterable)
    48. return self._length
    49. # 5、生成器长度提示(通常不准确,因为生成器是动态的)
    50. def my_generator(n):
    51. for i in range(n):
    52. yield i
    53. class GeneratorWrapper:
    54. def __init__(self, generator_func, *args, **kwargs):
    55. self.generator = generator_func(*args, **kwargs)
    56. self._hint = None
    57. def __iter__(self):
    58. return iter(self.generator)
    59. def __length_hint__(self):
    60. if self._hint is None:
    61. # 注意:这只是一个示例,对于真正的生成器可能不准确
    62. self._hint = sum(1 for _ in self.generator)
    63. return self._hint
    64. # 使用示例:GeneratorWrapper(my_generator, 10)
    65. # 6、模拟数据库查询结果
    66. class DatabaseQueryResult:
    67. def __init__(self, count):
    68. self.count = count
    69. def __length_hint__(self):
    70. return self.count
    71. # 7、文件行数预估(基于文件大小)
    72. class FileLineCounterApprox:
    73. def __init__(self, file_path, avg_line_length=100): # 假设平均行长为100字节
    74. self.file_path = file_path
    75. self.avg_line_length = avg_line_length
    76. def __length_hint__(self):
    77. with open(self.file_path, 'rb') as file:
    78. return file.seek(0, 2) // self.avg_line_length # 粗略估计
    79. # 8、树形结构节点数预估
    80. class TreeNode:
    81. def __init__(self, value, children=None):
    82. self.value = value
    83. self.children = children if children is not None else []
    84. def __length_hint__(self):
    85. # 假设这是一个完全二叉树,用于示例
    86. return (2 ** self.depth()) - 1 if self.is_full_binary_tree() else "unknown"
    87. def depth(self):
    88. # 需要实现一个计算树深度的函数
    89. pass
    90. def is_full_binary_tree(self):
    91. # 需要实现一个检查树是否是完全二叉树的函数
    92. pass
    93. # 注意:在实际应用中,树的长度(即节点数)可能需要递归遍历才能准确计算
    94. # 9、网络请求结果集大小预估
    95. class APIResult:
    96. def __init__(self, response_headers):
    97. self.response_headers = response_headers
    98. def __length_hint__(self):
    99. # 假设API响应头中包含了一个关于结果集大小的字段
    100. content_length = self.response_headers.get('X-Result-Set-Size', None)
    101. return int(content_length) if content_length is not None and content_length.isdigit() else "unknown"
    102. # 注意:这个预估是基于假设的HTTP头字段,实际API可能不会有这样的字段
    103. # 10、流式数据处理长度提示
    104. class StreamProcessor:
    105. def __init__(self, stream):
    106. self.stream = stream
    107. self._processed_count = 0
    108. def process(self, chunk_size=1024):
    109. # 处理流数据,这里只是模拟
    110. for _ in range(chunk_size):
    111. # 假设每次处理一个数据单元
    112. self._processed_count += 1
    113. def __length_hint__(self):
    114. # 流数据长度通常未知,但可以提供已处理的数量
    115. return self._processed_count
    116. # 注意:流数据的长度通常是未知的,除非有额外的信息或上下文
    117. # 11、自定义集合大小预估
    118. class CustomSet:
    119. def __init__(self, iterable=()):
    120. self._set = set(iterable)
    121. self._hint = None
    122. def add(self, item):
    123. self._set.add(item)
    124. self._hint = None # 清除长度提示缓存
    125. def remove(self, item):
    126. self._set.remove(item)
    127. self._hint = None
    128. def __iter__(self):
    129. return iter(self._set)
    130. def __len__(self):
    131. return len(self._set)
    132. def __length_hint__(self):
    133. if self._hint is None:
    134. self._hint = len(self) # 只有在需要时才计算长度
    135. return self._hint
    136. # 注意:在实际应用中,集合的大小可以直接通过len()函数获取,但这里展示了如何使用__length_hint__进行缓存

    45、__lshift__方法

    45-1、语法
    1. __lshift__(self, other, /)
    2. Return self << other
    45-2、参数

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

    45-2-2、 other(必须)表示与self进行左移操作的另一个对象或整数。

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

    45-3、功能

            用于定义对象与左移位运算符<<的行为。

    45-4、返回值

            返回一个与self类型相同或兼容的对象,该对象表示self对象左移other位之后的结果。

    45-5、说明

            如果类没有定义__lshift__方法,并且尝试使用左移位运算符<<对其实例进行操作,将会引发一个TypeError。

    45-6、用法
    1. # 045、__lshift__方法:
    2. # 1、二进制位移
    3. class BinaryShift:
    4. def __init__(self, value):
    5. self.value = value
    6. def __lshift__(self, other):
    7. return BinaryShift(self.value << other)
    8. if __name__ == '__main__':
    9. a = BinaryShift(4)
    10. b = a << 2 # 相当于 4 << 2 = 16
    11. print(b.value) # 输出 16
    12. # 2、整数列表左移
    13. class IntList:
    14. def __init__(self, values):
    15. self.values = values
    16. def __lshift__(self, other):
    17. if other < 0 or other >= len(self.values):
    18. raise ValueError("Invalid shift amount")
    19. return IntList(self.values[other:] + self.values[:other])
    20. if __name__ == '__main__':
    21. lst = IntList([3, 5, 6, 8, 10, 11, 24])
    22. shifted = lst << 2 # 相当于 [6, 8, 10, 11, 24, 3, 5]
    23. print(shifted.values) # 输出 [6, 8, 10, 11, 24, 3, 5]
    24. # 3、字符串左移
    25. class StringShift:
    26. def __init__(self, value):
    27. self.value = value
    28. def __lshift__(self, other):
    29. if other < 0:
    30. return StringShift(self.value[-other:] + self.value[:-other])
    31. elif other >= len(self.value):
    32. return StringShift(self.value)
    33. else:
    34. return StringShift(self.value[other:] + self.value[:other])
    35. if __name__ == '__main__':
    36. s = StringShift("hello")
    37. shifted = s << 2 # 相当于 "llohe"
    38. print(shifted.value) # 输出 "llohe"
    39. # 4、时间戳左移(模拟时间偏移)
    40. from datetime import datetime, timedelta
    41. class TimestampShift:
    42. def __init__(self, timestamp):
    43. self.timestamp = timestamp
    44. def __lshift__(self, other):
    45. # 假设 other 是天数
    46. return TimestampShift(self.timestamp + timedelta(days=other))
    47. if __name__ == '__main__':
    48. now = datetime.now()
    49. ts = TimestampShift(now)
    50. future = ts << 10 # 10天后的时间
    51. print(future.timestamp) # 输出10天后的日期时间
    52. # 5、图形对象的水平移动
    53. class Shape:
    54. def __init__(self, x, y):
    55. self.x = x
    56. self.y = y
    57. def __lshift__(self, other):
    58. return Shape(self.x + other, self.y)
    59. if __name__ == '__main__':
    60. rect = Shape(10, 24)
    61. moved = rect << 5 # 向右移动5个单位
    62. print(moved.x, moved.y) # 输出 15 24
    63. # 6、权重调整(模拟权重左移)
    64. class WeightedItem:
    65. def __init__(self, value, weight):
    66. self.value = value
    67. self.weight = weight
    68. def __lshift__(self, other):
    69. # 假设 other 是权重增加的因子(例如,左移1位相当于权重乘以2)
    70. return WeightedItem(self.value, self.weight * (2 ** other))
    71. if __name__ == '__main__':
    72. item = WeightedItem('apple', 1)
    73. item_with_higher_weight = item << 1 # 权重变为 2
    74. print(item_with_higher_weight.weight) # 输出 2
    75. # 7、颜色深度调整(模拟颜色通道值的左移)
    76. class Color:
    77. def __init__(self, r, g, b):
    78. self.r = r
    79. self.g = g
    80. self.b = b
    81. def __lshift__(self, other):
    82. # 假设 other 是亮度增加的因子(注意:这里需要确保值在有效范围内)
    83. return Color(min(self.r << other, 255), min(self.g << other, 255), min(self.b << other, 255))
    84. if __name__ == '__main__':
    85. red = Color(255, 0, 0)
    86. brighter_red = red << 1 # 增加亮度
    87. print(brighter_red.r, brighter_red.g, brighter_red.b) # 输出:255 0 0
    88. # 8、频率调整(模拟音频信号频率的左移)
    89. class AudioSignal:
    90. # 这里仅作为示例,实际音频处理会更复杂
    91. def __init__(self, frequencies):
    92. self.frequencies = frequencies
    93. def __lshift__(self, other):
    94. # 假设 other 是频率增加的因子(这在实际中是不准确的,仅作示例)
    95. return AudioSignal([freq * (2 ** other) for freq in self.frequencies])
    96. if __name__ == '__main__':
    97. signal = AudioSignal([100, 200, 300])
    98. higher_freq_signal = signal << 1 # 模拟频率加倍
    99. print(higher_freq_signal.frequencies) # 输出:[200, 400, 600]
    100. # 9、队列元素左移(删除头部元素并在尾部添加新元素)
    101. class Queue:
    102. def __init__(self):
    103. self.items = []
    104. def enqueue(self, item):
    105. self.items.append(item)
    106. def dequeue(self):
    107. if self.is_empty():
    108. raise IndexError("Queue is empty")
    109. return self.items.pop(0)
    110. def is_empty(self):
    111. return len(self.items) == 0
    112. # 模拟左移(删除头部并添加新元素)
    113. def __lshift__(self, new_item):
    114. self.dequeue()
    115. self.enqueue(new_item)
    116. if __name__ == '__main__':
    117. q = Queue()
    118. q.enqueue(1)
    119. q.enqueue(2)
    120. q.enqueue(3)
    121. print(q.items) # 输出 [1, 2, 3]
    122. q << 4 # 删除1并添加4
    123. print(q.items) # 输出 [2, 3, 4]
    124. # 10、价格调整(模拟折扣)
    125. class Price:
    126. def __init__(self, value):
    127. self.value = value
    128. def __lshift__(self, discount_factor):
    129. # 假设 discount_factor 是折扣的百分比(例如,左移1位代表打五折)
    130. # 注意:这里的实现仅作为示例,真实的折扣计算会更复杂
    131. return Price(self.value * (1 - discount_factor / 100))
    132. if __name__ == '__main__':
    133. original_price = Price(100)
    134. discounted_price = original_price << 50 # 假设代表打五折
    135. print(discounted_price.value) # 输出 50.0
    136. # 11、时间线事件的前移
    137. class TimelineEvent:
    138. def __init__(self, name, timestamp):
    139. self.name = name
    140. self.timestamp = timestamp
    141. def __lshift__(self, time_delta):
    142. # 将事件前移指定的时间量
    143. self.timestamp -= time_delta
    144. if __name__ == '__main__':
    145. event = TimelineEvent('Meeting', datetime.now())
    146. print(event.timestamp) # 输出当前时间
    147. event << timedelta(hours=1) # 将事件前移1小时
    148. print(event.timestamp) # 输出前移1小时后的时间
    149. # 12、图形界面中的元素左移
    150. class GUIElement:
    151. def __init__(self, x, y):
    152. self.x = x
    153. self.y = y
    154. def __lshift__(self, shift_amount):
    155. # 将元素向左移动指定的像素量
    156. self.x = max(0, self.x - shift_amount) # 确保元素不会移出容器的左侧边界
    157. def __repr__(self):
    158. # 为了更友好地打印GUIElement对象
    159. return f"GUIElement(x={self.x}, y={self.y})"
    160. # 假设的GUI容器类(仅用于演示)
    161. class GUIContainer:
    162. def __init__(self):
    163. self.elements = []
    164. def add_element(self, element):
    165. # 添加元素到容器中(这里只是简单地将元素添加到列表中)
    166. self.elements.append(element)
    167. # 主程序
    168. if __name__ == '__main__':
    169. # 创建一个GUI容器
    170. container = GUIContainer()
    171. # 创建一个GUI元素(按钮)并添加到容器中(虽然在这里我们并不真正添加到GUI中)
    172. button = GUIElement(100, 50)
    173. # 假设有一个add_element方法添加到容器中(这里我们手动调用)
    174. container.add_element(button)
    175. # 将按钮向左移动20像素
    176. button << 20 # 调用__lshift__方法
    177. # 打印按钮的新位置
    178. print(button) # 输出类似:GUIElement(x=80, y=50)

    46、__lt__方法

    46-1、语法
    1. __lt__(self, other, /)
    2. Return self < other
    46-2、参数

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

    46-2-2、 other(必须)表示与self进行比较的另一个对象。

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

    46-3、功能

            用于定义对象之间“小于”关系的行为。

    46-4、返回值

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

    46-5、说明

            如果没有在类中定义__lt__方法,并且尝试使用<运算符对其实例进行比较,将会引发一个TypeError,除非该类的实例是某个内置类型的子类(如int、float、str等),这些内置类型已经定义了它们自己的__lt__方法。

    46-6、用法
    1. # 046、__lt__方法:
    2. # 1、自定义整数类
    3. class MyInt:
    4. def __init__(self, value):
    5. self.value = value
    6. def __lt__(self, other):
    7. if isinstance(other, MyInt):
    8. return self.value < other.value
    9. elif isinstance(other, int):
    10. return self.value < other
    11. else:
    12. raise TypeError("Unsupported operand types for <: 'MyInt' and '{}'".format(type(other).__name__))
    13. if __name__ == '__main__':
    14. a = MyInt(5)
    15. b = MyInt(10)
    16. print(a < b) # True
    17. # 2、自定义字符串长度比较
    18. class StringLength:
    19. def __init__(self, s):
    20. self.s = s
    21. def __lt__(self, other):
    22. if isinstance(other, StringLength):
    23. return len(self.s) < len(other.s)
    24. elif isinstance(other, int):
    25. return len(self.s) < other
    26. else:
    27. raise TypeError("Unsupported operand types for <: 'StringLength' and '{}'".format(type(other).__name__))
    28. if __name__ == '__main__':
    29. s1 = StringLength("apple")
    30. s2 = StringLength("banana")
    31. print(s1 < s2) # True
    32. # 3、自定义日期类
    33. from datetime import date
    34. class MyDate:
    35. def __init__(self, year, month, day):
    36. self.date = date(year, month, day)
    37. def __lt__(self, other):
    38. if isinstance(other, MyDate):
    39. return self.date < other.date
    40. else:
    41. raise TypeError("Unsupported operand types for <: 'MyDate' and '{}'".format(type(other).__name__))
    42. if __name__ == '__main__':
    43. d1 = MyDate(2024, 3, 13)
    44. d2 = MyDate(2024, 6, 4)
    45. print(d1 < d2) # True
    46. # 4、自定义二维点类
    47. class Point:
    48. def __init__(self, x, y):
    49. self.x = x
    50. self.y = y
    51. def __lt__(self, other):
    52. if isinstance(other, Point):
    53. return (self.x, self.y) < (other.x, other.y)
    54. else:
    55. raise TypeError("Unsupported operand types for <: 'Point' and '{}'".format(type(other).__name__))
    56. if __name__ == '__main__':
    57. p1 = Point(3, 6)
    58. p2 = Point(5, 11)
    59. print(p1 < p2) # True
    60. # 5、自定义矩形面积比较
    61. class Rectangle:
    62. def __init__(self, width, height):
    63. self.width = width
    64. self.height = height
    65. @property
    66. def area(self):
    67. return self.width * self.height
    68. def __lt__(self, other):
    69. if isinstance(other, Rectangle):
    70. return self.area < other.area
    71. else:
    72. raise TypeError("Unsupported operand types for <: 'Rectangle' and '{}'".format(type(other).__name__))
    73. if __name__ == '__main__':
    74. rect1 = Rectangle(3, 6)
    75. rect2 = Rectangle(5, 11)
    76. print(rect1 < rect2) # True
    77. # 6、自定义字典按值排序比较(仅比较第一个值)
    78. class ValueSortedDict:
    79. def __init__(self, dict_items):
    80. self.dict_items = sorted(dict_items.items(), key=lambda x: x[1])
    81. def __lt__(self, other):
    82. if isinstance(other, ValueSortedDict):
    83. return self.dict_items[0][1] < other.dict_items[0][1]
    84. else:
    85. raise TypeError("Unsupported operand types for <: 'ValueSortedDict' and '{}'".format(type(other).__name__))
    86. if __name__ == '__main__':
    87. dict1 = {'a': 10, 'b': 24}
    88. dict2 = {'c': 10, 'd': 8}
    89. vsd1 = ValueSortedDict(dict1)
    90. vsd2 = ValueSortedDict(dict2)
    91. print(vsd1 < vsd2) # False
    92. # 7、自定义分数类,按分数值比较
    93. from fractions import Fraction
    94. class FractionWrapper:
    95. def __init__(self, numerator, denominator):
    96. self.fraction = Fraction(numerator, denominator)
    97. def __lt__(self, other):
    98. if isinstance(other, FractionWrapper):
    99. return self.fraction < other.fraction
    100. elif isinstance(other, Fraction):
    101. return self.fraction < other
    102. else:
    103. raise TypeError("Unsupported operand types for <: 'FractionWrapper' and '{}'".format(type(other).__name__))
    104. if __name__ == '__main__':
    105. frac1 = FractionWrapper(10, 24)
    106. frac2 = FractionWrapper(3, 6)
    107. print(frac1 < frac2) # True
    108. # 8、自定义复数类,按模长比较
    109. import math
    110. class ComplexNumber:
    111. def __init__(self, real, imag):
    112. self.real = real
    113. self.imag = imag
    114. @property
    115. def modulus(self):
    116. return math.sqrt(self.real ** 2 + self.imag ** 2)
    117. def __lt__(self, other):
    118. if isinstance(other, ComplexNumber):
    119. return self.modulus < other.modulus
    120. else:
    121. raise TypeError("Unsupported operand types for <: 'ComplexNumber' and '{}'".format(type(other).__name__))
    122. if __name__ == '__main__':
    123. c1 = ComplexNumber(3, 6)
    124. c2 = ComplexNumber(5, 11)
    125. print(c1 < c2) # True
    126. # 9、自定义时间戳类,按时间先后比较
    127. from datetime import datetime, timezone
    128. class Timestamp:
    129. def __init__(self, timestamp):
    130. self.timestamp = datetime.fromtimestamp(timestamp, tz=timezone.utc)
    131. def __lt__(self, other):
    132. if isinstance(other, Timestamp):
    133. return self.timestamp < other.timestamp
    134. elif isinstance(other, datetime):
    135. return self.timestamp < other
    136. else:
    137. raise TypeError("Unsupported operand types for <: 'Timestamp' and '{}'".format(type(other).__name__))
    138. if __name__ == '__main__':
    139. ts1 = Timestamp(1609459200) # 2021-01-01 00:00:00 UTC
    140. ts2 = Timestamp(1609545600) # 2021-01-02 00:00:00 UTC
    141. print(ts1 < ts2) # True
    142. # 10、自定义二维点类,按字典序比较
    143. class Point2D:
    144. def __init__(self, x, y):
    145. self.x = x
    146. self.y = y
    147. def __lt__(self, other):
    148. if not isinstance(other, Point2D):
    149. return NotImplemented
    150. if self.x < other.x:
    151. return True
    152. elif self.x == other.x and self.y < other.y:
    153. return True
    154. return False
    155. def __repr__(self):
    156. return f"Point2D({self.x}, {self.y})"
    157. if __name__ == '__main__':
    158. p1 = Point2D(1, 2)
    159. p2 = Point2D(2, 1)
    160. p3 = Point2D(1, 3)
    161. print(p1 < p2) # True
    162. print(p1 < p3) # True
    163. print(p2 < p3) # False
    164. # 11、自定义图书类,按价格或出版时间比较
    165. from datetime import datetime
    166. class Book:
    167. def __init__(self, title, author, price, publish_date):
    168. self.title = title
    169. self.author = author
    170. self.price = price
    171. self.publish_date = datetime.strptime(publish_date, '%Y-%m-%d')
    172. def __repr__(self):
    173. return f"Book(title={self.title}, author={self.author}, price={self.price}, publish_date={self.publish_date.strftime('%Y-%m-%d')})"
    174. def __lt_by_price__(self, other):
    175. if not isinstance(other, Book):
    176. return NotImplemented
    177. return self.price < other.price
    178. def __lt_by_publish_date__(self, other):
    179. if not isinstance(other, Book):
    180. return NotImplemented
    181. return self.publish_date < other.publish_date
    182. if __name__ == '__main__':
    183. book1 = Book("Python Programming", "Alice", 39.99, "2022-01-01")
    184. book2 = Book("Java for Beginners", "Bob", 29.99, "2021-05-15")
    185. book3 = Book("Database Management", "Charlie", 49.99, "2022-06-30")
    186. # 按价格比较
    187. print(book1.__lt_by_price__(book2)) # True,因为book1的价格比book2高
    188. print(book2.__lt_by_price__(book3)) # True,因为book2的价格比book3低
    189. # 按出版时间比较
    190. print(book1.__lt_by_publish_date__(book2)) # False,因为book1的出版时间比book2晚
    191. print(book2.__lt_by_publish_date__(book3)) # True,因为book2的出版时间比book3早
    192. # 12、自定义学生类,按成绩比较
    193. class Student:
    194. def __init__(self, name, score):
    195. self.name = name
    196. self.score = score
    197. def __repr__(self):
    198. return f"Student(name={self.name}, score={self.score})"
    199. def __lt__(self, other):
    200. if not isinstance(other, Student):
    201. return NotImplemented
    202. return self.score < other.score
    203. if __name__ == '__main__':
    204. student1 = Student("Myelsa", 85)
    205. student2 = Student("Bruce", 90)
    206. student3 = Student("Jimmy", 85)
    207. # 按成绩比较
    208. print(student1 < student2) # True,因为student1的成绩比student2低
    209. print(student1 < student3) # False,因为student1和student3的成绩相同
    210. print(student2 < student3) # False,因为student2的成绩比student3高

    五、推荐阅读

    1、Python筑基之旅

    2、Python函数之旅

    3、Python算法之旅

    4、博客个人主页

  • 相关阅读:
    力扣:155. 最小栈(Python3)
    【LeetCode算法系列题解】第46~50题
    【昇腾产品应用】英码科技EA500I基于昇腾Mind SDK实现实时人体关键点检测
    yolov7训练自己的数据集及报错处理
    搜维尔科技:Touch触觉式力反馈设备与Touch X力反馈设备对比分析
    使用 http-proxy 代理 HTTP 请求时遇到的 the requested url is invalid 错误消息
    机器学习——决策树与随机森林
    “五育”并举育人体系构建的实践研究课题实施方案
    阿里巴巴深入浅出Springboot文档送给你,简直建议收藏
    还在每天玩单调的控制台窗口?赶紧进来!!!用EasyX画出自己的优美窗口(万字教程,一文入门)
  • 原文地址:https://blog.csdn.net/ygb_1024/article/details/139422349