目录
一、概述
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的魔法方法需要不断地学习、实践和总结,只有通过不断地练习和积累经验,你才能更好地掌握这些强大的工具,并在实际项目中灵活运用它们。
四、魔法方法
50、__neg__方法
50-1、语法
- __neg__(self, /)
- -self
50-2、参数
50-2-1、self(必须):一个对实例对象本身的引用,在类的所有方法中都会自动传递。
50-2-2、/(可选):这是从Python 3.8开始引入的参数注解语法,它表示这个方法不接受任何位置参数(positional-only parameters)之后的关键字参数(keyword arguments)。
50-3、功能
用于定义对象的负值操作。
50-4、返回值
返回一个值,该值表示对象的负值。
50-5、说明
无
50-6、用法
- # 050、__neg__方法:
- # 1、整数包装类
- class IntWrapper:
- def __init__(self, value):
- self.value = value
- def __neg__(self):
- return IntWrapper(-self.value)
- def __repr__(self):
- return f'IntWrapper({self.value})'
- if __name__ == '__main__':
- w = IntWrapper(5)
- print(-w) # 输出: IntWrapper(-5)
-
- # 2、分数类
- from fractions import Fraction
- class FractionWrapper:
- def __init__(self, numerator, denominator):
- self.fraction = Fraction(numerator, denominator)
- def __neg__(self):
- return FractionWrapper(-self.fraction.numerator, self.fraction.denominator)
- def __repr__(self):
- return f'FractionWrapper({self.fraction.numerator}/{self.fraction.denominator})'
- if __name__ == '__main__':
- fw = FractionWrapper(1, 2)
- print(-fw) # 输出: FractionWrapper(-1/2)
-
- # 3、向量类(二维)
- class Vector2D:
- def __init__(self, x, y):
- self.x = x
- self.y = y
- def __neg__(self):
- return Vector2D(-self.x, -self.y)
- def __repr__(self):
- return f'Vector2D({self.x}, {self.y})'
- if __name__ == '__main__':
- v = Vector2D(1, 2)
- print(-v) # 输出: Vector2D(-1, -2)
-
- # 4、复数类
- class ComplexNumber:
- def __init__(self, real, imag):
- self.real = real
- self.imag = imag
- def __neg__(self):
- return ComplexNumber(-self.real, -self.imag)
- def __repr__(self):
- return f'ComplexNumber({self.real}, {self.imag})'
- if __name__ == '__main__':
- c = ComplexNumber(1, 2)
- print(-c) # 输出: ComplexNumber(-1, -2)
-
- # 5、矩阵类(简单示例)
- class Matrix:
- def __init__(self, data):
- self.data = data
- def __neg__(self):
- return Matrix([[-num for num in row] for row in self.data])
- def __repr__(self):
- return f'Matrix({self.data})'
- if __name__ == '__main__':
- m = Matrix([[1, 2], [3, 4]])
- print(-m) # 输出: Matrix([[-1, -2], [-3, -4]])
-
- # 6、时间间隔类
- from datetime import timedelta
- class TimeInterval:
- def __init__(self, days=0, seconds=0, microseconds=0, minutes=0, hours=0):
- # 注意:去除了 milliseconds 和 weeks,因为 timedelta 不支持这些参数
- total_seconds = seconds + minutes * 60 + hours * 3600
- self.delta = timedelta(days=days, seconds=total_seconds, microseconds=microseconds)
- def __neg__(self):
- # 注意:我们不能直接使用 total_seconds() 来创建一个新的 timedelta,因为它返回的是浮点数
- # 相反,我们创建一个新的 timedelta 对象,其秒数和微秒数是原对象的负数
- # 注意:这里简化了处理,没有考虑溢出问题
- negative_seconds = -self.delta.total_seconds()
- negative_days, remainder = divmod(negative_seconds, 86400) # 一天有86400秒
- negative_microseconds = int((-remainder % 1) * 1e6) # 计算剩余的微秒部分
- return TimeInterval(days=int(negative_days), seconds=int(remainder), microseconds=negative_microseconds)
- def __repr__(self):
- # 注意:timedelta 没有直接转换为字符串的优雅方式,我们可以使用 str(self.delta) 但它可能不够清晰
- # 这里我们手动构建字符串表示
- days, seconds = divmod(self.delta.total_seconds(), 86400)
- hours, remainder = divmod(seconds, 3600)
- minutes, seconds = divmod(remainder, 60)
- microseconds = self.delta.microseconds
- return f'TimeInterval(days={days}, hours={hours}, minutes={minutes}, seconds={seconds}, microseconds={microseconds})'
- if __name__ == '__main__':
- ti = TimeInterval(days=1)
- print(-ti) # 输出类似: TimeInterval(days=-1, hours=0, minutes=0, seconds=0, microseconds=0)
-
- # 7、温度类(摄氏度)
- class Temperature:
- def __init__(self, celsius):
- self.celsius = celsius
- def __neg__(self):
- return Temperature(-self.celsius)
- def __repr__(self):
- return f'Temperature({self.celsius}°C)'
- if __name__ == '__main__':
- t = Temperature(25)
- print(-t) # 输出: Temperature(-25°C)
-
- # 8、货币类
- class Money:
- def __init__(self, amount, currency='USD'):
- self.amount = amount
- self.currency = currency
- def __neg__(self):
- return Money(-self.amount, self.currency)
- def __repr__(self):
- return f'Money({self.amount} {self.currency})'
- if __name__ == '__main__':
- m = Money(100, 'EUR')
- print(-m) # 输出: Money(-100 EUR)
-
- # 9、坐标点类(三维)
- class Point3D:
- def __init__(self, x, y, z):
- self.x = x
- self.y = y
- self.z = z
- def __neg__(self):
- return Point3D(-self.x, -self.y, -self.z)
- def __repr__(self):
- return f'Point3D({self.x}, {self.y}, {self.z})'
- if __name__ == '__main__':
- p = Point3D(1, 2, 3)
- print(-p) # 输出: Point3D(-1, -2, -3)
-
- # 10、矩形类(表示面积和位置)
- class Rectangle:
- def __init__(self, width, height, x=0, y=0):
- self.width = width
- self.height = height
- self.x = x
- self.y = y
- def __neg__(self):
- # 在这个上下文中,- 可能没有明确的含义,但为了示例,我们可以返回一个具有负面积的矩形
- return Rectangle(-self.width, -self.height, self.x, self.y)
- def __repr__(self):
- return f'Rectangle(width={self.width}, height={self.height}, x={self.x}, y={self.y})'
- if __name__ == '__main__':
- r = Rectangle(5, 10, 1, 2)
- print(-r) # 输出: Rectangle(width=-5, height=-10, x=1, y=2)
-
- # 11、有理数类
- class Rational:
- def __init__(self, numerator, denominator):
- self.numerator = numerator
- self.denominator = denominator
- def __neg__(self):
- return Rational(-self.numerator, self.denominator)
- def __repr__(self):
- return f'Rational({self.numerator}/{self.denominator})'
- if __name__ == '__main__':
- rat = Rational(3, 4)
- print(-rat) # 输出: Rational(-3/4)
-
- # 12、区间类(表示数值范围)
- class Interval:
- def __init__(self, start, end):
- self.start = start
- self.end = end
- def __neg__(self):
- # 在这个上下文中,- 可能没有明确的含义,但为了示例,我们可以返回反向的区间
- return Interval(-self.end, -self.start)
- def __repr__(self):
- return f'Interval({self.start}, {self.end})'
- if __name__ == '__main__':
- i = Interval(1, 5)
- print(-i) # 输出: Interval(-5, -1)
51、__new__方法
51-1、语法
- __new__(cls, *args, **kwargs)
- Create and return a new object
51-2、参数
51-2-1、cls(必须):一个指向调用__new__的类的引用。
51-2-2、 *args(可选):表示传递给__new__方法的可变参数列表。
51-2-3、**kwargs(可选):表示传递给__new__方法的关键字参数字典。
51-3、功能
用于创建并返回(或有时不返回)一个类的实例对象。
51-4、返回值
返回一个新创建的实例对象。
51-5、说明
__new__方法的功能主要有以下几点:
51-5-1、控制对象的创建
通过覆盖__new__方法,你可以完全控制对象的创建过程。例如,你可以在创建对象之前进行一些检查,或者根据某些条件选择创建不同类型的对象。
51-5-2、实现单例模式
通过确保__new__方法总是返回相同的对象实例,你可以实现单例模式,即确保一个类只有一个实例,并提供一个全局访问点。
51-5-3、与元类交互
当你编写元类时,__new__方法会被用来创建类对象本身,而不是类的实例。在这种情况下,你可以控制类对象的创建和初始化过程
51-6、用法
- # 051、__new__方法:
- # 1、单例模式
- class Singleton:
- _instance = None
- def __new__(cls, *args, **kwargs):
- if cls._instance is None:
- cls._instance = super().__new__(cls)
- return cls._instance
-
- # 2、计数实例的类
- class CountedInstance:
- _instances = 0
- def __new__(cls, *args, **kwargs):
- instance = super().__new__(cls)
- cls._instances += 1
- return instance
- @classmethod
- def instances(cls):
- return cls._instances
-
- # 3、自定义元类中
- class Meta(type):
- def __new__(mcls, name, bases, attrs):
- attrs['some_attribute'] = 'value from metaclass'
- return super().__new__(mcls, name, bases, attrs)
- class MyClass(metaclass=Meta):
- pass
- print(MyClass.some_attribute) # 输出: value from metaclass
-
- # 4、依赖注入
- class DependencyInjector:
- def __new__(cls, dependency, *args, **kwargs):
- instance = super().__new__(cls)
- instance.dependency = dependency
- return instance
- def __init__(self, *args, **kwargs):
- # 注意: __init__ 可能不会被调用,因为依赖已经在 __new__ 中设置
- pass
-
- # 5、延迟初始化
- class LazyInit:
- def __new__(cls, *args, **kwargs):
- instance = super().__new__(cls)
- instance._initialized = False
- return instance
- def __init__(self, *args, **kwargs):
- if not self._initialized:
- # 初始化代码...
- self._initialized = True
52、__next__方法
52-1、语法
- __next__(self, /)
- Implement next(self)
52-2、参数
52-2-1、self(必须):一个对实例对象本身的引用,在类的所有方法中都会自动传递。
52-2-3、/(可选):这是从Python 3.8开始引入的参数注解语法,它表示这个方法不接受任何位置参数(positional-only parameters)之后的关键字参数(keyword arguments)。
52-3、功能
用于返回迭代器中的下一个元素。
52-4、返回值
返回值通常是迭代器序列中的下一个元素。
52-5、说明
如果迭代器中没有更多的元素可供迭代(即已到达序列的末尾),则抛出一个StopIteration异常。
52-6、用法
- # 052、__next__方法:
- # 1、简单的列表迭代器
- class SimpleIterator:
- def __init__(self, max_value):
- self.value = 0
- self.max_value = max_value
- def __iter__(self):
- return self
- def __next__(self):
- if self.value < self.max_value:
- current_value = self.value
- self.value += 1
- return current_value
- else:
- raise StopIteration
- iterator = SimpleIterator(5)
- for i in iterator:
- print(i)
- # 0
- # 1
- # 2
- # 3
- # 4
-
- # 2、斐波那契数列迭代器
- class Fibonacci:
- def __init__(self, max_value):
- self.max_value = max_value
- self.a, self.b = 0, 1
- def __iter__(self):
- return self
- def __next__(self):
- if self.a > self.max_value:
- raise StopIteration
- fib = self.a
- self.a, self.b = self.b, self.a + self.b
- return fib
- fib = Fibonacci(100)
- for num in fib:
- print(num)
- # 0
- # 1
- # 1
- # 2
- # 3
- # 5
- # 8
- # 13
- # 21
- # 34
- # 55
- # 89
-
- # 3、文件逐行读取迭代器
- class LineIterator:
- def __init__(self, filename):
- self.file = open(filename, 'r')
- def __iter__(self):
- return self
- def __next__(self):
- line = self.file.readline()
- if not line:
- raise StopIteration
- return line.strip()
- def __del__(self):
- self.file.close()
-
- it = LineIterator('test.txt')
- for line in it:
- print(line)
-
- # 4、字符串迭代器(按字符)
- class StringIterator:
- def __init__(self, string):
- self.string = string
- self.index = 0
- def __iter__(self):
- return self
- def __next__(self):
- if self.index >= len(self.string):
- raise StopIteration
- char = self.string[self.index]
- self.index += 1
- return char
- str_it = StringIterator('hello')
- for char in str_it:
- print(char)
- # h
- # e
- # l
- # l
- # o
-
- # 5、字典迭代器(按键)
- class DictKeyIterator:
- def __init__(self, dictionary):
- self.dictionary = dictionary
- self.keys = iter(dictionary.keys())
- def __iter__(self):
- return self
- def __next__(self):
- return next(self.keys)
- d = {'a': 1, 'b': 2, 'c': 3}
- it = DictKeyIterator(d)
- for key in it:
- print(key)
- # a
- # b
- # c
-
- # 6、自定义集合迭代器(按特定顺序,如降序)
- class SortedSetIterator:
- def __init__(self, set_data):
- self.set_data = sorted(set_data, reverse=True)
- self.index = 0
- def __iter__(self):
- return self
- def __next__(self):
- if self.index >= len(self.set_data):
- raise StopIteration
- item = self.set_data[self.index]
- self.index += 1
- return item
- s = {3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5}
- it = SortedSetIterator(s)
- for item in it:
- print(item)
- # 9
- # 6
- # 5
- # 4
- # 3
- # 2
- # 1
五、推荐阅读
1、Python筑基之旅
2、Python函数之旅
3、Python算法之旅
4、博客个人主页



评论记录:
回复评论: