赞
踩
目录
魔法方法(Magic Methods/Special Methods,也称特殊方法或双下划线方法)是Python中一类具有特殊命名规则的方法,它们的名称通常以双下划线(`__`)开头和结尾。
魔法方法用于在特定情况下自动被Python解释器调用,而不需要显式地调用它们,它们提供了一种机制,让你可以定义自定义类时具有与内置类型相似的行为。
魔法方法允许开发者重载Python中的一些内置操作或函数的行为,从而为自定义的类添加特殊的功能。
1-1、__init__(self, [args...]):在创建对象时初始化属性。
1-2、__new__(cls, [args...]):在创建对象时控制实例的创建过程(通常与元类一起使用)。
1-3、__del__(self):在对象被销毁前执行清理操作,如关闭文件或释放资源。
2-1、__add__(self, other)、__sub__(self, other)、__mul__(self, other)等:自定义对象之间的算术运算。
2-2、__eq__(self, other)、__ne__(self, other)、__lt__(self, other)等:定义对象之间的比较操作。
3-1、__str__(self):定义对象的字符串表示,常用于print()函数。
3-2、__repr__(self):定义对象的官方字符串表示,用于repr()函数和交互式解释器。
4-1、__getitem__(self, key)、__setitem__(self, key, value)、__delitem__(self, key):用于实现类似列表或字典的索引访问、设置和删除操作。
4-2、__len__(self):返回对象的长度或元素个数。
5-1、__call__(self, [args...]):允许对象像函数一样被调用。
6-1、__enter__(self)、__exit__(self, exc_type, exc_val, exc_tb):用于实现上下文管理器,如with语句中的对象。
7-1、__getattr__, __setattr__, __delattr__:这些方法允许对象在访问或修改不存在的属性时执行自定义操作。
7-2、描述符(Descriptors)是实现了__get__, __set__, 和__delete__方法的对象,它们可以控制对另一个对象属性的访问。
8-1、__iter__和__next__:这些方法允许对象支持迭代操作,如使用for循环遍历对象。
8-2、__aiter__, __anext__:这些是异步迭代器的魔法方法,用于支持异步迭代。
9-1、__int__(self)、__float__(self)、__complex__(self):定义对象到数值类型的转换。
9-2、__index__(self):定义对象用于切片时的整数转换。
10-1、__copy__和__deepcopy__:允许对象支持浅复制和深复制操作。
10-2、__getstate__和__setstate__:用于自定义对象的序列化和反序列化过程。
11-1、__metaclass__(Python 2)或元类本身(Python 3):允许自定义类的创建过程,如动态创建类、修改类的定义等。
12-1、__init__和__new__:用于初始化对象或控制对象的创建过程。
12-2、__init_subclass__:在子类被创建时调用,允许在子类中执行一些额外的操作。
13-1、__instancecheck__和__subclasscheck__:用于自定义isinstance()和issubclass()函数的行为。
14-1、你可以通过继承内置的Exception类来创建自定义的异常类,并定义其特定的行为。
要学好Python的魔法方法,你可以遵循以下方法及步骤:
首先确保你对Python的基本语法、数据类型、类和对象等概念有深入的理解,这些是理解魔法方法的基础。
仔细阅读Python官方文档中关于魔法方法的部分,文档会详细解释每个魔法方法的作用、参数和返回值。你可以通过访问Python的官方网站或使用help()函数在Python解释器中查看文档。
为每个魔法方法编写简单的示例代码,以便更好地理解其用法和效果,通过实际编写和运行代码,你可以更直观地感受到魔法方法如何改变对象的行为。
在实际项目中尝试使用魔法方法。如,你可以创建一个自定义的集合类,使用__getitem__、__setitem__和__delitem__方法来实现索引操作。只有通过实践应用,你才能更深入地理解魔法方法的用途和重要性。
阅读开源项目或他人编写的代码,特别是那些使用了魔法方法的代码,这可以帮助你学习如何在实际项目中使用魔法方法。通过分析他人代码中的魔法方法使用方式,你可以学习到一些新的技巧和最佳实践。
参与Python社区的讨论,与其他开发者交流关于魔法方法的使用经验和技巧,在社区中提问或回答关于魔法方法的问题,这可以帮助你更深入地理解魔法方法并发现新的应用场景。
Python语言和其生态系统不断发展,新的魔法方法和功能可能会不断被引入,保持对Python社区的关注,及时学习新的魔法方法和最佳实践。
多做练习,通过编写各种使用魔法方法的代码来巩固你的理解,定期总结你学到的知识和经验,形成自己的知识体系。
在使用魔法方法时,要注意不同Python版本之间的兼容性差异,确保你的代码在不同版本的Python中都能正常工作。
虽然魔法方法非常强大,但过度使用可能会导致代码难以理解和维护,在编写代码时,要权衡使用魔法方法的利弊,避免滥用。
总之,学好Python的魔法方法需要不断地学习、实践和总结,只有通过不断地练习和积累经验,你才能更好地掌握这些强大的工具,并在实际项目中灵活运用它们。
- __ceil__(self, /)
- Return the ceiling as an Integral
6-2-1、self(必须):调用该方法的对象本身。
6-2-2、/(可选):这是从Python 3.8开始引入的参数注解语法,它表示这个方法不接受任何位置参数(positional-only parameters)之后的关键字参数(keyword arguments)。
用于定义对象的上限取整行为。
返回一个不大于其调用者(即调用该方法的对象)的最小整数,即它返回调用者的上限或最小上界整数。
在大多数情况下,你不需要为你的类实现 __ceil__ 方法,除非你正在创建一个需要自定义上限行为的数值类型。
- # 006、__ceil__方法:
- class CustomNumber:
- def __init__(self, value):
- self.value = float(value)
- def __ceil__(self):
- """
- 模拟上限取整行为
- """
- import math
- return math.ceil(self.value)
- def __repr__(self):
- """
- 提供一个友好的字符串表示
- """
- return f"CustomNumber({self.value})"
- # 使用示例
- cn = CustomNumber(3.14)
- # 直接调用 __ceil__ 方法(通常不推荐这样做,因为它是一个“私有”方法)
- print(cn.__ceil__()) # 输出: 4
- # 更好的做法:提供一个公共的 ceil 方法
- class BetterCustomNumber(CustomNumber):
- def ceil(self):
- """
- 提供一个公共的上限取整方法
- """
- return self.__ceil__()
- bcn = BetterCustomNumber(3.14)
- print(bcn.ceil()) # 输出: 4
- __complex__(self, /)
- Convert this value to exact type complex
7-2-1、self(必须):调用该方法的对象本身。
7-2-2、/(可选):这是从Python 3.8开始引入的参数注解语法,它表示这个方法不接受任何位置参数(positional-only parameters)之后的关键字参数(keyword arguments)。
用于定义当对象被需要转换为复数类型(complex)时的行为。
返回一个复数,或者抛出一个异常(如果无法转换为复数)。
无
- # 007、__complex__方法:
- # 1、简单的复数类
- class SimpleComplex:
- def __init__(self, real, imag):
- self.real = real
- self.imag = imag
- def __complex__(self):
- return complex(self.real, self.imag)
- # 使用
- c = SimpleComplex(3, 4)
- print(complex(c)) # 输出: (3+4j)
-
- # 2、从字符串解析复数
- class ComplexFromString:
- def __init__(self, s):
- self.s = s
- def __complex__(self):
- return complex(self.s)
- # 使用
- c = ComplexFromString("3+4j")
- print(complex(c)) # 输出: (3+4j)
-
- # 3、极坐标到直角坐标的复数
- import math
- class PolarComplex:
- def __init__(self, r, theta):
- self.r = r
- self.theta = theta
- def __complex__(self):
- return complex(self.r * math.cos(self.theta), self.r * math.sin(self.theta))
- # 使用
- c = PolarComplex(5, math.pi / 4)
- print(complex(c)) # 输出类似: (3.5355339059327378+3.5355339059327378j)
-
- # 4、复数运算的结果
- class ComplexOperationResult:
- def __init__(self, real, imag):
- self.real = real
- self.imag = imag
- def __complex__(self):
- return complex(self.real, self.imag)
- # 假设这是某个复数运算的结果
- result = ComplexOperationResult(1, 2)
- print(complex(result)) # 输出: (1+2j)
-
- # 5、从列表构造复数
- class ComplexFromList:
- def __init__(self, lst):
- if len(lst) != 2:
- raise ValueError("List must contain exactly two elements")
- self.real, self.imag = lst
- def __complex__(self):
- return complex(self.real, self.imag)
- # 使用
- c = ComplexFromList([3, 4])
- print(complex(c)) # 输出: (3+4j)
-
- # 6、从字典构造复数
- class ComplexFromDict:
- def __init__(self, dct):
- if 'real' not in dct or 'imag' not in dct:
- raise ValueError("Dictionary must contain 'real' and 'imag' keys")
- self.real = dct['real']
- self.imag = dct['imag']
- def __complex__(self):
- return complex(self.real, self.imag)
- # 使用
- c = ComplexFromDict({'real': 3, 'imag': 4})
- print(complex(c)) # 输出: (3+4j)
-
- # 7、复数与自定义单位的结合
- class ComplexWithUnit:
- def __init__(self, real, imag, unit):
- self.real = real
- self.imag = imag
- self.unit = unit
- def __complex__(self):
- # 假设我们忽略单位并只返回复数值
- return complex(self.real, self.imag)
- # 使用
- c = ComplexWithUnit(3, 4, "V") # V for voltage
- print(complex(c)) # 输出: (3+4j)
-
- # 8、复数与自定义精度的结合
- class ComplexWithPrecision:
- def __init__(self, real, imag, precision):
- self.real = round(real, precision)
- self.imag = round(imag, precision)
- self.precision = precision
- def __complex__(self):
- # 直接使用已经四舍五入到指定精度的实部和虚部
- return complex(self.real, self.imag)
- def __repr__(self):
- # 提供一个友好的字符串表示形式
- return f"ComplexWithPrecision({self.real}, {self.imag}, precision={self.precision})"
- # 使用
- c = ComplexWithPrecision(3.14159, 2.71828, 2)
- print(complex(c)) # 输出类似: (3.14+2.72j),注意这里由于四舍五入可能得到2.72而不是2.71
- print(c) # 输出: ComplexWithPrecision(3.14, 2.72, precision=2)
- __contains__(self, item, /)
- Return item in self
8-2-1、self(必须):调用该方法的对象本身。
8-2-2、item(必须):传递给in
运算符的值,用于检查它是否存在于自定义对象中。
8-2-3、/(可选):这是从Python 3.8开始引入的参数注解语法,它表示这个方法不接受任何位置参数(positional-only parameters)之后的关键字参数(keyword arguments)。
用于定义当使用 in 关键字进行成员检查时对象的行为。
返回一个布尔值(True
或 False
),表示item
是否存在于对象中。
在 __contains__
方法的实现中,你应该编写逻辑来判断item
是否存在于你的对象中。如果item
存在,则返回True
;如果item
不存在,则返回False
。
- # 008、__contains__方法:
- # 1、简单的列表类
- class MyList:
- def __init__(self, items):
- self.items = items
- def __contains__(self, item):
- return item in self.items
- # 使用
- my_list = MyList([1, 2, 3])
- print(1 in my_list) # 输出: True
-
- # 2、字典,检查键是否存在
- class MyDict:
- def __init__(self, items):
- self.items = items
- def __contains__(self, key):
- return key in self.items
- # 使用
- my_dict = MyDict({'a': 1, 'b': 2})
- print('a' in my_dict) # 输出: True
-
- # 3、字符串类,检查子串
- class MyString:
- def __init__(self, s):
- self.s = s
- def __contains__(self, substring):
- return substring in self.s
- # 使用
- my_string = MyString('hello, world')
- print('world' in my_string) # 输出: True
-
- # 4、自定义集合类
- class MySet:
- def __init__(self, items):
- self.items = set(items)
- def __contains__(self, item):
- return item in self.items
- # 使用
- my_set = MySet({1, 2, 3})
- print(2 in my_set) # 输出: True
-
- # 5、区间类,检查数值是否在区间内
- class Interval:
- def __init__(self, start, end):
- self.start = start
- self.end = end
- def __contains__(self, value):
- return self.start <= value <= self.end
- # 使用
- interval = Interval(1, 5)
- print(3 in interval) # 输出: True
-
- # 6、自定义树形结构,检查节点是否存在
- class TreeNode:
- def __init__(self, value):
- self.value = value
- self.children = []
- def add_child(self, node):
- self.children.append(node)
- def __contains__(self, value):
- if self.value == value:
- return True
- for child in self.children:
- if value in child:
- return True
- return False
- # 使用
- root = TreeNode(1)
- child1 = TreeNode(2)
- root.add_child(child1)
- print(2 in root) # 输出: True
-
- # 7、检查文件名的后缀
- class File:
- def __init__(self, filename):
- self.filename = filename
- def __contains__(self, suffix):
- return self.filename.endswith(suffix)
- # 使用
- file = File('example.txt')
- print('.txt' in file) # 输出: True
-
- # 8、检查字符串是否包含大写字母
- class StringChecker:
- def __init__(self, s):
- self.s = s
- def __contains__(self, char_type):
- if char_type == 'uppercase':
- return any(c.isupper() for c in self.s)
- else:
- raise ValueError("Unknown char_type")
- # 使用
- checker = StringChecker('Hello, World!')
- print('uppercase' in checker) # 输出: True
-
- # 9、自定义数字范围类,支持步长
- class Range:
- def __init__(self, start, end, step=1):
- self.start = start
- self.end = end
- self.step = step
- # 确保步长不为0,并且如果end小于start,步长应该为负数
- if self.step == 0:
- raise ValueError("Step cannot be zero")
- if (self.end < self.start and self.step > 0) or (self.end > self.start and self.step < 0):
- raise ValueError("Invalid range with given step")
- def __contains__(self, value):
- # 确保value在范围内
- if self.step > 0 and (value < self.start or value > self.end):
- return False
- if self.step < 0 and (value > self.start or value < self.end):
- return False
- # 检查value是否是范围内的某个步长点
- if (value - self.start) % self.step == 0:
- return True
- return False
- # 使用示例
- my_range = Range(1, 10, 2) # 创建一个范围从1到10,步长为2的Range对象
- print(3 in my_range) # 输出: True,因为3是范围内的步长点(1, 3, 5, ..., 9)
- print(4 in my_range) # 输出: False,因为4不是步长为2的Range对象中的点
- print(11 in my_range) # 输出: False,因为11超出了范围
- my_range_negative = Range(10, 1, -2) # 创建一个从10到1,步长为-2的Range对象
- print(8 in my_range_negative) # 输出: True,因为8是范围内的步长点(10, 8, 6, 4, 2)
- __delattr__(self, name, /)
- Implement delattr(self, name)
9-2-1、self(必须):调用该方法的对象本身。
9-2-2、name(必须):表示要被删除的属性名。
9-2-3、/(可选):这是从Python 3.8开始引入的参数注解语法,它表示这个方法不接受任何位置参数(positional-only parameters)之后的关键字参数(keyword arguments)。
用于定义当尝试删除对象的属性时发生的操作。
无
当你使用del
语句删除一个对象的属性时,该操作是一个表达式语句(expression statement),而不是一个表达式(expression),因此,它本身不产生任何值(即没有返回值)。
- # 009、__delattr__方法:
- # 1、禁止删除特定属性
- class ProhibitedDeletion:
- def __init__(self):
- self.protected_attr = "This cannot be deleted"
- def __delattr__(self, name):
- if name == "protected_attr":
- raise AttributeError("Cannot delete protected_attr")
- else:
- super().__delattr__(name)
-
- # 2、记录属性删除
- class DeletionLogger:
- def __init__(self):
- self.log = []
- def __delattr__(self, name):
- self.log.append(f"Deleting attribute: {name}")
- super().__delattr__(name)
-
- # 3、删除前验证
- class ValidatedDeletion:
- def __init__(self):
- self.valid_attr = True
- def __delattr__(self, name):
- if name == "valid_attr" and not getattr(self, name, False):
- raise ValueError("Cannot delete invalid attribute")
- super().__delattr__(name)
-
- # 4、触发清理函数
- class CleanupOnDeletion:
- def __init__(self):
- self.resource = "Some resource"
- def cleanup(self):
- print("Cleaning up resource")
- def __delattr__(self, name):
- if name == "resource":
- self.cleanup()
- super().__delattr__(name)
-
- # 5、删除前检查类型
- class TypedDeletion:
- def __init__(self):
- self.int_attr = 10
- def __delattr__(self, name):
- if name == "int_attr" and not isinstance(getattr(self, name, None), int):
- raise TypeError("int_attr must be an integer to delete")
- super().__delattr__(name)
-
- # 6、替换为默认值
- class DefaultOnDeletion:
- def __init__(self):
- self.replaceable_attr = "Initial value"
- def __delattr__(self, name):
- if name == "replaceable_attr":
- setattr(self, name, "Default value")
- else:
- super().__delattr__(name)
-
- # 7、延迟删除
- class DelayedDeletion:
- def __init__(self):
- self.delayed_attr = "Delayed deletion"
- self.deletion_scheduled = False
- def __delattr__(self, name):
- if name == "delayed_attr":
- self.deletion_scheduled = True
- print("Deletion of delayed_attr is scheduled")
- else:
- super().__delattr__(name)
- def perform_deletions(self):
- if self.deletion_scheduled:
- del self.delayed_attr
- self.deletion_scheduled = False
-
- # 8、递归删除(递归删除需要小心处理,以避免无限递归或栈溢出)
- class RecursiveDeletion:
- def __init__(self):
- self.nested = RecursiveDeletion()
- def __delattr__(self, name):
- if name == "nested" and isinstance(getattr(self, name, None), RecursiveDeletion):
- print("Recursively deleting nested object")
- delattr(getattr(self, name), "nested") # 假设嵌套对象也有相同的结构
- super().__delattr__(name)
-
- # 9、属性删除后的回调
- class CallbackOnDeletion:
- def __init__(self):
- self.attr = "To be deleted"
- self.callbacks = []
- def register_callback(self, callback):
- self.callbacks.append(callback)
- def __delattr__(self, name):
- if name == "attr":
- for callback in self.callbacks:
- callback()
- super().__delattr__(name)
-
- # 10、属性删除通知
- class NotifyingClass:
- def __init__(self):
- self.some_attr = "This attribute can be deleted"
- def __delattr__(self, name):
- if hasattr(self, name): # 确保属性确实存在
- print(f"Attribute '{name}' is being deleted.")
- super().__delattr__(name) # 调用父类的__delattr__方法来实际删除属性
- else:
- print(f"Attribute '{name}' does not exist.")
- # 使用示例
- obj = NotifyingClass()
- print(obj.some_attr) # 输出: This attribute can be deleted
- del obj.some_attr # 输出: Attribute 'some_attr' is being deleted.
- # 尝试删除不存在的属性
- del obj.non_existent # 输出: Attribute 'non_existent' does not exist.
- __delete__(self, instance, /)
- Delete an attribute of instance
10-2-1、self(必须):描述符类的实例(即描述符对象自身)。
10-2-2、instance(必须):拥有描述符属性的实例。
10-2-3、/(可选):这是从Python 3.8开始引入的参数注解语法,它表示这个方法不接受任何位置参数(positional-only parameters)之后的关键字参数(keyword arguments)。
用于处理在拥有者(owner)类或其实例上删除描述符属性时的行为。
该方法并不返回一个值,或者说它的返回值是None。
当从拥有者实例上删除描述符属性时,这个实例会作为instance参数传入;如果在类级别(而不是实例级别)删除描述符,则instance参数会被设置为None(因为类本身没有实例)。
虽然__delete__
方法允许你控制删除操作,但它并不能真正地从内存中删除描述符对象本身。
- # 010、__delete__方法:
- # 1、基本用法
- class Descriptor:
- def __delete__(self, instance):
- print(f"Deleting descriptor for instance {instance}")
- class MyClass:
- attr = Descriptor()
- obj = MyClass()
- del obj.attr # 输出: Deleting descriptor for instance <__main__.MyClass object at 0x000001E97E39F7D0>
-
- # 2、带有状态清理
- class Resource:
- def __init__(self):
- self.is_open = True
- def close(self):
- self.is_open = False
- class DescriptorWithCleanup:
- def __init__(self):
- self.resource = Resource()
- def __delete__(self, instance):
- if self.resource.is_open:
- self.resource.close()
- print("Resource closed")
- class MyClass:
- attr = DescriptorWithCleanup()
- obj = MyClass()
- del obj.attr # 输出: Resource closed
-
- # 3、检查实例
- class Descriptor:
- def __delete__(self, instance):
- if instance is None:
- print("Deleting at class level is not allowed")
- else:
- print(f"Deleting descriptor for instance {instance}")
- class MyClass:
- attr = Descriptor()
- # del MyClass.attr # 这会触发 "Deleting at class level is not allowed"
- obj = MyClass()
- del obj.attr # 输出: Deleting descriptor for instance <__main__.MyClass object at 0x000001845CC61150>
-
- # 4、记录删除操作
- class LoggingDescriptor:
- def __delete__(self, instance):
- with open("log.txt", "a") as file:
- file.write(f"Deleting descriptor for instance {instance}\n")
-
- # 5、抛出异常
- class ProtectedDescriptor:
- def __delete__(self, instance):
- raise AttributeError("This descriptor cannot be deleted")
- del obj.attr # 这会触发 AttributeError: This descriptor cannot be deleted
-
- # 6、使用weakref
- import weakref
- class WeakRefDescriptor:
- def __init__(self):
- self._refs = weakref.WeakSet()
- def __get__(self, instance, owner):
- if instance is not None:
- self._refs.add(instance)
- return instance
- def __delete__(self, instance):
- if instance is not None:
- self._refs.discard(instance)
- print(f"Instance {instance} removed from weak references")
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。