找回密码
 会员注册
查看: 20|回复: 0

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

[复制链接]

3

主题

0

回帖

10

积分

新手上路

积分
10
发表于 2024-9-10 06:35:00 | 显示全部楼层 |阅读模式
目录一、概述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、定义        魔法方法(MagicMethods/SpecialMethods,也称特殊方法或双下划线方法)是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__(Python2)或元类本身(Python3):允许自定义类的创建过程,如动态创建类、修改类的定义等。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、持续学习        ython语言和其生态系统不断发展,新的魔法方法和功能可能会不断被引入,保持对Python社区的关注,及时学习新的魔法方法和最佳实践。8、练习与总结        多做练习,通过编写各种使用魔法方法的代码来巩固你的理解,定期总结你学到的知识和经验,形成自己的知识体系。9、注意兼容性        在使用魔法方法时,要注意不同Python版本之间的兼容性差异,确保你的代码在不同版本的Python中都能正常工作。10、避免过度使用        虽然魔法方法非常强大,但过度使用可能会导致代码难以理解和维护,在编写代码时,要权衡使用魔法方法的利弊,避免滥用。        总之,学好Python的魔法方法需要不断地学习、实践和总结,只有通过不断地练习和积累经验,你才能更好地掌握这些强大的工具,并在实际项目中灵活运用它们。四、魔法方法44、__length_hint__方法44-1、语法__length_hint__(self,/)Privatemethodreturninganestimateoflen(list(it))44-2、参数44-2-1、self(必须):一个对实例对象本身的引用,在类的所有方法中都会自动传递。44-2-2、/(可选):这是从Python3.8开始引入的参数注解语法,它表示这个方法不接受任何位置参数(positional-onlyparameters)之后的关键字参数(keywordarguments)。44-3、功能    为那些需要知道迭代器大致长度的函数或方法提供一个长度提示。44-4、返回值        返回一个整数或None。44-5、说明  __length_hint__方法应该返回一个整数或None:44-5-1、如果返回整数,它应该是一个对迭代器长度的合理估计,这个估计可能并不总是准确的,但它应该尽可能接近实际长度。44-5-2、如果迭代器长度未知或无法合理估计,则应返回None。44-6、用法#044、__length_hint__方法:#1、简单的列表包装器classMyListWrapper:def__init__(self,lst):self.lst=lstdef__length_hint__(self):returnlen(self.lst)#2、迭代器长度提示classMyIterator:def__init__(self,numbers):self.numbers=numbersself.index=0def__iter__(self):returnselfdef__next__(self):ifself.indexself.end:raiseStopIterationcurrent=self.startself.start+=1returncurrentdef__length_hint__(self):returnself.end-self.start+1ifself.start=len(self.values):raiseValueError("Invalidshiftamount")returnIntList(self.values[other:]+self.values[ther])if__name__=='__main__':lst=IntList([3,5,6,8,10,11,24])shifted=lst<< 2 # 相当于 [6, 8, 10, 11, 24, 3, 5] print(shifted.values) # 输出 [6, 8, 10, 11, 24, 3, 5] # 3、字符串左移class StringShift: def __init__(self, value): self.value = value def __lshift__(self, other): if other < 0: return StringShift(self.value[-other:] + self.value[:-other]) elif other >=len(self.value):returnStringShift(self.value)else:returnStringShift(self.value[other:]+self.value[ther])if__name__=='__main__':s=StringShift("hello")shifted=s<< 2 # 相当于 "llohe" print(shifted.value) # 输出 "llohe" # 4、时间戳左移(模拟时间偏移)from datetime import datetime, timedeltaclass TimestampShift: def __init__(self, timestamp): self.timestamp = timestamp def __lshift__(self, other): # 假设 other 是天数 return TimestampShift(self.timestamp + timedelta(days=other))if __name__ == '__main__': now = datetime.now() ts = TimestampShift(now) future = ts << 10 # 10天后的时间 print(future.timestamp) # 输出10天后的日期时间 # 5、图形对象的水平移动class Shape: def __init__(self, x, y): self.x = x self.y = y def __lshift__(self, other): return Shape(self.x + other, self.y)if __name__ == '__main__': rect = Shape(10, 24) moved = rect << 5 # 向右移动5个单位 print(moved.x, moved.y) # 输出 15 24 # 6、权重调整(模拟权重左移)class WeightedItem: def __init__(self, value, weight): self.value = value self.weight = weight def __lshift__(self, other): # 假设 other 是权重增加的因子(例如,左移1位相当于权重乘以2) return WeightedItem(self.value, self.weight * (2 ** other))if __name__ == '__main__': item = WeightedItem('apple', 1) item_with_higher_weight = item << 1 # 权重变为 2 print(item_with_higher_weight.weight) # 输出 2 # 7、颜色深度调整(模拟颜色通道值的左移)class Color: def __init__(self, r, g, b): self.r = r self.g = g self.b = b def __lshift__(self, other): # 假设 other 是亮度增加的因子(注意:这里需要确保值在有效范围内) return Color(min(self.r << other, 255), min(self.g << other, 255), min(self.b << other, 255))if __name__ == '__main__': red = Color(255, 0, 0) brighter_red = red << 1 # 增加亮度 print(brighter_red.r, brighter_red.g, brighter_red.b) # 输出:255 0 0 # 8、频率调整(模拟音频信号频率的左移)class AudioSignal: # 这里仅作为示例,实际音频处理会更复杂 def __init__(self, frequencies): self.frequencies = frequencies def __lshift__(self, other): # 假设 other 是频率增加的因子(这在实际中是不准确的,仅作示例) return AudioSignal([freq * (2 ** other) for freq in self.frequencies])if __name__ == '__main__': signal = AudioSignal([100, 200, 300]) higher_freq_signal = signal << 1 # 模拟频率加倍 print(higher_freq_signal.frequencies) # 输出:[200, 400, 600] # 9、队列元素左移(删除头部元素并在尾部添加新元素)class Queue: def __init__(self): self.items = [] def enqueue(self, item): self.items.append(item) def dequeue(self): if self.is_empty(): raise IndexError("Queue is empty") return self.items.pop(0) def is_empty(self): return len(self.items) == 0 # 模拟左移(删除头部并添加新元素) def __lshift__(self, new_item): self.dequeue() self.enqueue(new_item)if __name__ == '__main__': q = Queue() q.enqueue(1) q.enqueue(2) q.enqueue(3) print(q.items) # 输出 [1, 2, 3] q << 4 # 删除1并添加4 print(q.items) # 输出 [2, 3, 4] # 10、价格调整(模拟折扣)class Price: def __init__(self, value): self.value = value def __lshift__(self, discount_factor): # 假设 discount_factor 是折扣的百分比(例如,左移1位代表打五折) # 注意:这里的实现仅作为示例,真实的折扣计算会更复杂 return Price(self.value * (1 - discount_factor / 100))if __name__ == '__main__': original_price = Price(100) discounted_price = original_price << 50 # 假设代表打五折 print(discounted_price.value) # 输出 50.0 # 11、时间线事件的前移class TimelineEvent: def __init__(self, name, timestamp): self.name = name self.timestamp = timestamp def __lshift__(self, time_delta): # 将事件前移指定的时间量 self.timestamp -= time_deltaif __name__ == '__main__': event = TimelineEvent('Meeting', datetime.now()) print(event.timestamp) # 输出当前时间 event << timedelta(hours=1) # 将事件前移1小时 print(event.timestamp) # 输出前移1小时后的时间 # 12、图形界面中的元素左移class GUIElement: def __init__(self, x, y): self.x = x self.y = y def __lshift__(self, shift_amount): # 将元素向左移动指定的像素量 self.x = max(0, self.x - shift_amount) # 确保元素不会移出容器的左侧边界 def __repr__(self): # 为了更友好地打印GUIElement对象 return f"GUIElement(x={self.x}, y={self.y})"# 假设的GUI容器类(仅用于演示)class GUIContainer: def __init__(self): self.elements = [] def add_element(self, element): # 添加元素到容器中(这里只是简单地将元素添加到列表中) self.elements.append(element)# 主程序if __name__ == '__main__': # 创建一个GUI容器 container = GUIContainer() # 创建一个GUI元素(按钮)并添加到容器中(虽然在这里我们并不真正添加到GUI中) button = GUIElement(100, 50) # 假设有一个add_element方法添加到容器中(这里我们手动调用) container.add_element(button) # 将按钮向左移动20像素 button << 20 # 调用__lshift__方法 # 打印按钮的新位置 print(button) # 输出类似:GUIElement(x=80, y=50)'运行运行 46、__lt__方法 46-1、语法 __lt__(self, other, /) 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、用法 # 046、__lt__方法:# 1、自定义整数类class MyInt: def __init__(self, value): self.value = value def __lt__(self, other): if isinstance(other, MyInt): return self.value < other.value elif isinstance(other, int): return self.value < other else: raise TypeError("Unsupported operand types for <: 'MyInt' and '{}'".format(type(other).__name__))if __name__ == '__main__': a = MyInt(5) b = MyInt(10) print(a < b) # True # 2、自定义字符串长度比较class StringLength: def __init__(self, s): self.s = s def __lt__(self, other): if isinstance(other, StringLength): return len(self.s) < len(other.s) elif isinstance(other, int): return len(self.s) < other else: raise TypeError("Unsupported operand types for <: 'StringLength' and '{}'".format(type(other).__name__))if __name__ == '__main__': s1 = StringLength("apple") s2 = StringLength("banana") print(s1 < s2) # True # 3、自定义日期类from datetime import dateclass MyDate: def __init__(self, year, month, day): self.date = date(year, month, day) def __lt__(self, other): if isinstance(other, MyDate): return self.date < other.date else: raise TypeError("Unsupported operand types for <: 'MyDate' and '{}'".format(type(other).__name__))if __name__ == '__main__': d1 = MyDate(2024, 3, 13) d2 = MyDate(2024, 6, 4) print(d1 < d2) # True # 4、自定义二维点类class Point: def __init__(self, x, y): self.x = x self.y = y def __lt__(self, other): if isinstance(other, Point): return (self.x, self.y) < (other.x, other.y) else: raise TypeError("Unsupported operand types for <: 'Point' and '{}'".format(type(other).__name__))if __name__ == '__main__': p1 = Point(3, 6) p2 = Point(5, 11) print(p1 < p2) # True # 5、自定义矩形面积比较class Rectangle: def __init__(self, width, height): self.width = width self.height = height @property def area(self): return self.width * self.height def __lt__(self, other): if isinstance(other, Rectangle): return self.area < other.area else: raise TypeError("Unsupported operand types for <: 'Rectangle' and '{}'".format(type(other).__name__))if __name__ == '__main__': rect1 = Rectangle(3, 6) rect2 = Rectangle(5, 11) print(rect1 < rect2) # True # 6、自定义字典按值排序比较(仅比较第一个值)class ValueSortedDict: def __init__(self, dict_items): self.dict_items = sorted(dict_items.items(), key=lambda x: x[1]) def __lt__(self, other): if isinstance(other, ValueSortedDict): return self.dict_items[0][1] < other.dict_items[0][1] else: raise TypeError("Unsupported operand types for <: 'ValueSortedDict' and '{}'".format(type(other).__name__))if __name__ == '__main__': dict1 = {'a': 10, 'b': 24} dict2 = {'c': 10, 'd': 8} vsd1 = ValueSortedDict(dict1) vsd2 = ValueSortedDict(dict2) print(vsd1 < vsd2) # False # 7、自定义分数类,按分数值比较from fractions import Fractionclass FractionWrapper: def __init__(self, numerator, denominator): self.fraction = Fraction(numerator, denominator) def __lt__(self, other): if isinstance(other, FractionWrapper): return self.fraction < other.fraction elif isinstance(other, Fraction): return self.fraction < other else: raise TypeError("Unsupported operand types for <: 'FractionWrapper' and '{}'".format(type(other).__name__))if __name__ == '__main__': frac1 = FractionWrapper(10, 24) frac2 = FractionWrapper(3, 6) print(frac1 < frac2) # True # 8、自定义复数类,按模长比较import mathclass ComplexNumber: def __init__(self, real, imag): self.real = real self.imag = imag @property def modulus(self): return math.sqrt(self.real ** 2 + self.imag ** 2) def __lt__(self, other): if isinstance(other, ComplexNumber): return self.modulus < other.modulus else: raise TypeError("Unsupported operand types for <: 'ComplexNumber' and '{}'".format(type(other).__name__))if __name__ == '__main__': c1 = ComplexNumber(3, 6) c2 = ComplexNumber(5, 11) print(c1 < c2) # True # 9、自定义时间戳类,按时间先后比较from datetime import datetime, timezoneclass Timestamp: def __init__(self, timestamp): self.timestamp = datetime.fromtimestamp(timestamp, tz=timezone.utc) def __lt__(self, other): if isinstance(other, Timestamp): return self.timestamp < other.timestamp elif isinstance(other, datetime): return self.timestamp < other else: raise TypeError("Unsupported operand types for <: 'Timestamp' and '{}'".format(type(other).__name__))if __name__ == '__main__': ts1 = Timestamp(1609459200) # 2021-01-01 00:00:00 UTC ts2 = Timestamp(1609545600) # 2021-01-02 00:00:00 UTC print(ts1 < ts2) # True # 10、自定义二维点类,按字典序比较class Point2D: def __init__(self, x, y): self.x = x self.y = y def __lt__(self, other): if not isinstance(other, Point2D): return NotImplemented if self.x < other.x: return True elif self.x == other.x and self.y < other.y: return True return False def __repr__(self): return f"Point2D({self.x}, {self.y})"if __name__ == '__main__': p1 = Point2D(1, 2) p2 = Point2D(2, 1) p3 = Point2D(1, 3) print(p1 < p2) # True print(p1 < p3) # True print(p2 < p3) # False # 11、自定义图书类,按价格或出版时间比较from datetime import datetimeclass Book: def __init__(self, title, author, price, publish_date): self.title = title self.author = author self.price = price self.publish_date = datetime.strptime(publish_date, '%Y-%m-%d') def __repr__(self): return f"Book(title={self.title}, author={self.author}, price={self.price}, publish_date={self.publish_date.strftime('%Y-%m-%d')})" def __lt_by_price__(self, other): if not isinstance(other, Book): return NotImplemented return self.price < other.price def __lt_by_publish_date__(self, other): if not isinstance(other, Book): return NotImplemented return self.publish_date < other.publish_dateif __name__ == '__main__': book1 = Book("Python Programming", "Alice", 39.99, "2022-01-01") book2 = Book("Java for Beginners", "Bob", 29.99, "2021-05-15") book3 = Book("Database Management", "Charlie", 49.99, "2022-06-30") # 按价格比较 print(book1.__lt_by_price__(book2)) # True,因为book1的价格比book2高 print(book2.__lt_by_price__(book3)) # True,因为book2的价格比book3低 # 按出版时间比较 print(book1.__lt_by_publish_date__(book2)) # False,因为book1的出版时间比book2晚 print(book2.__lt_by_publish_date__(book3)) # True,因为book2的出版时间比book3早 # 12、自定义学生类,按成绩比较class Student: def __init__(self, name, score): self.name = name self.score = score def __repr__(self): return f"Student(name={self.name}, score={self.score})" def __lt__(self, other): if not isinstance(other, Student): return NotImplemented return self.score < other.scoreif __name__ == '__main__': student1 = Student("Myelsa", 85) student2 = Student("Bruce", 90) student3 = Student("Jimmy", 85) # 按成绩比较 print(student1 < student2) # True,因为student1的成绩比student2低 print(student1 < student3) # False,因为student1和student3的成绩相同 print(student2 < student3) # False,因为student2的成绩比student3高'运行运行 五、推荐阅读 1、Python筑基之旅 2、Python函数之旅 3、Python算法之旅 4、博客个人主页
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 会员注册

本版积分规则

QQ|手机版|心飞设计-版权所有:微度网络信息技术服务中心 ( 鲁ICP备17032091号-12 )|网站地图

GMT+8, 2025-1-7 06:39 , Processed in 1.074867 second(s), 25 queries .

Powered by Discuz! X3.5

© 2001-2025 Discuz! Team.

快速回复 返回顶部 返回列表