目录
![]()
![]()
![]()
一、概述
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的魔法方法需要不断地学习、实践和总结,只有通过不断地练习和积累经验,你才能更好地掌握这些强大的工具,并在实际项目中灵活运用它们。
![]()
四、魔法方法
59、__reduce__方法
59-1、语法
- __reduce__(self, /)
- Helper for pickle
59-2、参数
59-2-1、self(必须):一个对实例对象本身的引用,在类的所有方法中都会自动传递。
59-2-2、/(可选):这是从Python 3.8开始引入的参数注解语法,它表示这个方法不接受任何位置参数(positional-only parameters)之后的关键字参数(keyword arguments)。
59-3、功能
用于在反序列化时重新创建对象。
59-4、返回值
返回一个元组,其中至少包含两个元素:一个可调用对象(通常是类本身或一个工厂函数)和一个参数元组,用于在反序列化时重新创建对象。在某些情况下,它还可以返回第三个元素,即一个状态字典,用于存储对象的额外状态信息。
59-5、说明
无
59-6、用法
- # 059、__reduce__方法:
- # 1、简单的自定义对象
- import pickle
- class SimpleObject:
- def __init__(self, value):
- self.value = value
- def __reduce__(self):
- return (SimpleObject, (self.value,))
- if __name__ == '__main__':
- obj = SimpleObject(42)
- serialized = pickle.dumps(obj)
- deserialized = pickle.loads(serialized)
- print(deserialized.value) # 输出: 42
-
- # 2、带有复杂属性的对象
- class ComplexObject:
- def __init__(self, a, b, c):
- self.a = a
- self.b = b
- self.c = c
- def __reduce__(self):
- return (ComplexObject, (self.a, self.b, self.c))
- if __name__ == '__main__':
- obj = ComplexObject(1, 2, 3)
- serialized = pickle.dumps(obj)
- deserialized = pickle.loads(serialized)
- print(deserialized.a, deserialized.b, deserialized.c) # 输出: 1 2 3
-
- # 3、带有可变属性的对象
- class MutableObject:
- def __init__(self, lst):
- self.lst = lst
- def __reduce__(self):
- return (MutableObject, (list(self.lst),))
- if __name__ == '__main__':
- obj = MutableObject([1, 2, 3])
- serialized = pickle.dumps(obj)
- deserialized = pickle.loads(serialized)
- print(deserialized.lst) # 输出: [1, 2, 3]
-
- # 4、带有缓存的对象(简化版)
- import pickle
- class CachedObject:
- def __init__(self, value):
- self.value = value
- self._cache = None
- def get_cached_value(self):
- # 假设这里有一个复杂的计算过程,我们使用简单的赋值作为示例
- if self._cache is None:
- self._cache = self.value * 2
- return self._cache
- def __reduce__(self):
- # 序列化时不保存缓存,因为它可以通过值重新计算
- return (CachedObject, (self.value,))
- if __name__ == '__main__':
- obj = CachedObject(10)
- print(obj.get_cached_value()) # 输出: 20
- serialized = pickle.dumps(obj)
- deserialized = pickle.loads(serialized)
- print(deserialized.get_cached_value()) # 输出: 20,尽管缓存没有序列化,但值重新计算了
60、__reduce_ex__方法
60-1、语法
- __reduce_ex__(self, protocol, /)
- Helper for pickle
60-2、参数
60-2-1、self(必须):一个对实例对象本身的引用,在类的所有方法中都会自动传递。
60-2-2、 protocol(必须):一个整数,指定了pickle模块所使用的序列化协议版本。
60-2-3、/(可选): 这是从Python 3.8开始引入的参数注解语法,它表示这个方法不接受任何位置参数(positional-only parameters)之后的关键字参数(keyword arguments)。
60-3、功能
允许你根据所使用的序列化协议(由protocol参数指定)来定制序列化行为。
60-4、返回值
返回一个元组,其中至少包含两个元素:一个可调用对象(通常是类本身或一个工厂函数)和一个参数元组,用于在反序列化时重新创建对象。在某些情况下,它还可以返回第三个元素,即一个状态字典,用于存储对象的额外状态信息。
60-5、说明
Python 支持多种不同的序列化协议,每种协议都有其特定的特性和限制。例如,protocol=0是最早的协议,它只支持Python 1.x和2.x中的一些基本类型;而protocol=4(Python 3.4+)则支持更多的类型,并且具有更好的性能和更小的序列化大小。
60-6、用法
- # 060、__reduce_ex__方法:
- # 1、简单的自定义对象
- import pickle
- class SimpleObject:
- def __init__(self, value):
- self.value = value
- def __reduce_ex__(self, protocol):
- return (SimpleObject, (self.value,))
- if __name__ == '__main__':
- obj = SimpleObject(42)
- serialized = pickle.dumps(obj)
- deserialized = pickle.loads(serialized)
- print(deserialized.value) # 输出: 42
-
- # 2、带有版本控制的序列化
- import pickle
- class VersionedObject:
- def __init__(self, value, version=1):
- self.value = value
- self.version = version
- def __reduce_ex__(self, protocol):
- return (VersionedObject, (self.value, self.version), {'_version': self.version})
- if __name__ == '__main__':
- obj = VersionedObject(42, 2)
- serialized = pickle.dumps(obj)
- deserialized = pickle.loads(serialized)
- print(deserialized.value, deserialized.version) # 输出: 42 2
-
- # 3、处理不同的pickle协议版本
- import pickle
- class ProtocolAwareObject:
- def __init__(self, value):
- self.value = value
- def __reduce_ex__(self, protocol):
- if protocol < 4:
- # 对于较旧的pickle协议,可能需要进行特殊处理
- return (ProtocolAwareObject, (self.value.encode(),), {'_encoding': 'utf-8'})
- else:
- # 对于较新的pickle协议,可以直接序列化
- return (ProtocolAwareObject, (self.value,))
- if __name__ == '__main__':
- obj = ProtocolAwareObject('Hello, World!')
- serialized = pickle.dumps(obj, protocol=3) # 使用较旧的协议
- deserialized = pickle.loads(serialized, encoding='utf-8') # 需要指定编码
- print(deserialized.value) # 输出: b'Hello, World!'
- serialized = pickle.dumps(obj, protocol=4) # 使用较新的协议
- deserialized = pickle.loads(serialized) # 无需指定编码
- print(deserialized.value) # 输出: Hello, World!
-
- # 4、带有动态属性的对象
- import pickle
- class DynamicObject:
- def __init__(self, **kwargs):
- self.__dict__.update(kwargs)
- def __reduce_ex__(self, protocol):
- return (DynamicObject, (), self.__dict__)
- if __name__ == '__main__':
- obj = DynamicObject(a=1, b=2)
- serialized = pickle.dumps(obj)
- deserialized = pickle.loads(serialized)
- print(deserialized.a, deserialized.b) # 输出: 1 2
-
- # 5、带有时间戳的对象
- import pickle
- from datetime import datetime
- class TimestampedObject:
- def __init__(self, value, timestamp=None):
- self.value = value
- self.timestamp = timestamp or datetime.now()
- def reduce_ex(self, protocol):
- # 使用当前时间戳作为默认值来保持一致性
- return (TimestampedObject, (self.value, self.timestamp), None)
- if __name__ == '__main__':
- obj = TimestampedObject(42)
- serialized = pickle.dumps(obj)
- deserialized = pickle.loads(serialized)
- print(deserialized.value, deserialized.timestamp) # 输出: 类似于42 2024-06-05 21:07:49.708817
61、__repr__方法
61-1、语法
- __repr__(self, /)
- Return repr(self)
61-2、参数
61-2-1、self(必须):一个对实例对象本身的引用,在类的所有方法中都会自动传递。
61-2-2、/(可选):这是从Python 3.8开始引入的参数注解语法,它表示这个方法不接受任何位置参数(positional-only parameters)之后的关键字参数(keyword arguments)。
61-3、功能
用于返回一个对象的“官方”字符串表示,这个表示应该是一个有效的Python表达式,当它被 eval() 函数评估时,能够重新创建该对象的一个等价实例。
61-4、返回值
返回一个字符串,这个字符串应该是一个有效的Python表达式,用于重新创建该对象的一个等价实例。
61-5、说明
由于eval(repr(p))通常会尝试执行返回的字符串作为Python代码,因此__repr__方法返回的字符串必须是安全的,并且不能包含任何可能导致意外的副作用的代码。
61-6、用法
- # 061、__repr__方法:
- # 1、简单的整数封装类
- class IntWrapper:
- def __init__(self, value):
- self.value = value
- def __repr__(self):
- return f"IntWrapper({self.value})"
-
- # 2、复数封装类
- class ComplexWrapper:
- def __init__(self, real, imag):
- self.real = real
- self.imag = imag
- def __repr__(self):
- return f"ComplexWrapper({self.real}, {self.imag})"
-
- # 3、列表封装类
- class ListWrapper:
- def __init__(self, lst):
- self.lst = lst
- def __repr__(self):
- return f"ListWrapper({self.lst})"
-
- # 4、矩形类(包含宽度和高度)
- class Rectangle:
- def __init__(self, width, height):
- self.width = width
- self.height = height
- def __repr__(self):
- return f"Rectangle(width={self.width}, height={self.height})"
-
- # 5、分数类(分子和分母)
- from fractions import Fraction
- class FractionWrapper:
- def __init__(self, numerator, denominator):
- self.fraction = Fraction(numerator, denominator)
- def __repr__(self):
- return f"FractionWrapper({self.fraction.numerator}/{self.fraction.denominator})"
-
- # 6、日期类(年、月、日)
- from datetime import date
- class DateWrapper:
- def __init__(self, year, month, day):
- self.date = date(year, month, day)
- def __repr__(self):
- return f"DateWrapper({self.date.year}, {self.date.month}, {self.date.day})"
-
- # 7、自定义字典类
- class CustomDict:
- def __init__(self, **kwargs):
- self.data = kwargs
- def __repr__(self):
- return f"CustomDict({self.data})"
-
- # 8、点的二维坐标类
- class Point2D:
- def __init__(self, x, y):
- self.x = x
- self.y = y
- def __repr__(self):
- return f"Point2D(x={self.x}, y={self.y})"
-
- # 9、员工类(包含姓名和ID)
- class Employee:
- def __init__(self, name, id):
- self.name = name
- self.id = id
- def __repr__(self):
- return f"Employee(name='{self.name}', id={self.id})"
-
- # 10、栈类(使用列表作为底层数据结构)
- class Stack:
- def __init__(self):
- self.items = []
- def __repr__(self):
- return f"Stack({self.items})"
-
- # 11、集合封装类(包含额外方法)
- class SetWrapper:
- def __init__(self, elements):
- self.elements = set(elements)
- def __repr__(self):
- return f"SetWrapper({self.elements})"
-
- # 12、计数器类(使用字典来计数)
- from collections import Counter
- class CounterWrapper:
- def __init__(self, *args, **kwargs):
- self.counter = Counter(*args, **kwargs)
- def __repr__(self):
- return f"CounterWrapper({self.counter})"
评论记录:
回复评论: