目录
![]()
![]()
![]()
一、概述
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的魔法方法需要不断地学习、实践和总结,只有通过不断地练习和积累经验,你才能更好地掌握这些强大的工具,并在实际项目中灵活运用它们。
![]()
四、魔法方法
74、__subclasses__方法
74-1、语法
- __subclasses__(self, /)
- Return a list of immediate subclasses
74-2、参数
74-2-1、self(必须):一个对实例对象本身的引用,在类的所有方法中都会自动传递。
74-2-2、 /(可选):这是从Python 3.8开始引入的参数注解语法,它表示这个方法不接受任何位置参数(positional-only parameters)之后的关键字参数(keyword arguments)。
74-3、功能
检索并返回一个包含给定类(即self)所有直接子类的列表。
74-4、返回值
返回一个列表,列表中的元素是给定类的直接子类类型对象。
74-5、说明
如果没有任何子类,那么返回的列表将是空的。
74-6、用法
- # 074、__subclasses__方法:
- # 1、游戏角色类
- class Character:
- pass
- class Warrior(Character):
- pass
- class Mage(Character):
- pass
- print(Character.__subclasses__()) # 输出:[
, ] -
- # 2、动物分类
- class Animal:
- pass
- class Mammal(Animal):
- pass
- class Bird(Animal):
- pass
- print(Animal.__subclasses__()) # 输出:[
, ] -
- # 3、数据库模型
- class BaseModel:
- pass
- class User(BaseModel):
- pass
- class Product(BaseModel):
- pass
- print(BaseModel.__subclasses__()) # 输出:[
, ] -
- # 4、图形绘制
- class Shape:
- pass
- class Circle(Shape):
- pass
- class Rectangle(Shape):
- pass
- print(Shape.__subclasses__()) # 输出:[
, ] -
- # 5、汽车类型
- class Car:
- pass
- class ElectricCar(Car):
- pass
- class GasolineCar(Car):
- pass
- print(Car.__subclasses__()) # 输出:[
, ] -
- # 6、支付方式
- class PaymentMethod:
- pass
- class CreditCard(PaymentMethod):
- pass
- class DebitCard(PaymentMethod):
- pass
- print(PaymentMethod.__subclasses__()) # 输出:[
, ] -
- # 7、文件系统
- class FileSystemObject:
- pass
- class File(FileSystemObject):
- pass
- class Directory(FileSystemObject):
- pass
- print(FileSystemObject.__subclasses__()) # 输出:[
, ] -
- # 8、数学运算
- class MathOperation:
- pass
- class Addition(MathOperation):
- pass
- class Subtraction(MathOperation):
- pass
- print(MathOperation.__subclasses__()) # 输出:[
, ] -
- # 9、用户权限
- class Permission:
- pass
- class ReadPermission(Permission):
- pass
- class WritePermission(Permission):
- pass
- print(Permission.__subclasses__()) # 输出:[
, ] -
- # 10、食物分类
- class Food:
- pass
- class Fruit(Food):
- pass
- class Vegetable(Food):
- pass
- print(Food.__subclasses__()) # 输出:[
, ] -
- # 11、颜色分类
- class Color:
- pass
- class PrimaryColor(Color):
- pass
- class SecondaryColor(Color):
- pass
- print(Color.__subclasses__()) # 输出:[
, ] -
- # 12、网络协议
- class Protocol:
- pass
- class TCP(Protocol):
- pass
- class UDP(Protocol):
- pass
- print(Protocol.__subclasses__()) # 输出:[
, ]
75、__truediv__方法
75-1、语法
- __truediv__(self, other, /)
- Return self / other
75-2、参数
75-2-1、self(必须):一个对实例对象本身的引用,在类的所有方法中都会自动传递。
75-2-2、other(必须):表示除法操作的第二个操作数。当你写a / b时,a是self,而b是other。
75-2-3、 /(可选):这是从Python 3.8开始引入的参数注解语法,它表示这个方法不接受任何位置参数(positional-only parameters)之后的关键字参数(keyword arguments)。
75-3、功能
用于定义对象之间的除法操作的行为。
75-4、返回值
返回一个表示除法结果的对象。这个对象可以是任何类型,但通常它会返回与调用该方法的对象相同类型的结果,以保持类型的一致性。
75-5、说明
无
75-6、用法
- # 075、__truediv__方法:
- # 1、分数四则运算
- from fractions import Fraction
- class MyFraction:
- def __init__(self, numerator, denominator=1):
- # 确保分母不为0
- if denominator == 0:
- raise ValueError("Denominator cannot be zero")
- # 使用内置的Fraction类进行分数的创建和化简
- self.fraction = Fraction(numerator, denominator)
- def __str__(self):
- # 返回分数的字符串表示
- return str(self.fraction)
- def __add__(self, other):
- # 加法运算
- if isinstance(other, MyFraction):
- return MyFraction(self.fraction + other.fraction)
- elif isinstance(other, (int, float)):
- # 假设整数或浮点数与分数相加时,整数或浮点数作为分数的分子
- return MyFraction(self.fraction + Fraction(other))
- else:
- raise TypeError("Unsupported operand types for +: 'MyFraction' and '{}'".format(type(other).__name__))
- def __sub__(self, other):
- # 减法运算
- if isinstance(other, MyFraction):
- return MyFraction(self.fraction - other.fraction)
- elif isinstance(other, (int, float)):
- return MyFraction(self.fraction - Fraction(other))
- else:
- raise TypeError("Unsupported operand types for -: 'MyFraction' and '{}'".format(type(other).__name__))
- def __mul__(self, other):
- # 乘法运算
- if isinstance(other, MyFraction):
- return MyFraction(self.fraction * other.fraction)
- elif isinstance(other, (int, float)):
- return MyFraction(self.fraction * Fraction(other))
- else:
- raise TypeError("Unsupported operand types for *: 'MyFraction' and '{}'".format(type(other).__name__))
- def __truediv__(self, other):
- # 除法运算
- if isinstance(other, MyFraction):
- return MyFraction(self.fraction / other.fraction)
- elif isinstance(other, (int, float)):
- return MyFraction(self.fraction / Fraction(other))
- else:
- raise TypeError("Unsupported operand types for /: 'MyFraction' and '{}'".format(type(other).__name__))
- if __name__ == '__main__':
- f1 = MyFraction(1, 2) # 1/2
- f2 = MyFraction(2, 3) # 2/3
- f3 = f1 + f2 # 1/2 + 2/3 = 7/6
- f4 = f1 - f2 # 1/2 - 2/3 = -1/6
- f5 = f1 * f2 # 1/2 * 2/3 = 1/3
- f6 = f1 / f2 # 1/2 / 2/3 = 3/4
- print(f"f1 + f2 = {f3}")
- print(f"f1 - f2 = {f4}")
- print(f"f1 * f2 = {f5}")
- print(f"f1 / f2 = {f6}")
- # f1 + f2 = 7/6
- # f1 - f2 = -1/6
- # f1 * f2 = 1/3
- # f1 / f2 = 3/4
-
- # 2、矩阵类(实现两个矩阵之间的除法,通常这指的是矩阵的逆或矩阵与向量的除法)
- import numpy as np
- class Matrix:
- def __init__(self, data):
- self.data = np.array(data)
- def __truediv__(self, other):
- # 这里为了简化,我们只实现矩阵与向量的除法(即解线性方程组)
- if isinstance(other, Matrix) and other.data.ndim == 1:
- # 使用numpy的linalg.solve方法解线性方程组
- return Matrix(np.linalg.solve(self.data, other.data))
- else:
- raise TypeError("Unsupported operand types for /: 'Matrix' and '{}'".format(type(other).__name__))
- def __str__(self):
- return str(self.data)
- if __name__ == '__main__':
- A = Matrix([[1, 2], [3, 4]])
- b = Matrix([1, 2])
- x = A / b # 解线性方程组 Ax = b
- print(x) # 输出解向量x
-
- # 3、时间类(实现两个时间间隔之间的除法)
- from datetime import timedelta
- class TimeInterval:
- def __init__(self, days=0, seconds=0, microseconds=0, milliseconds=0, minutes=0, hours=0, weeks=0):
- self.delta = timedelta(days=days, seconds=seconds, microseconds=microseconds, milliseconds=milliseconds,
- minutes=minutes, hours=hours, weeks=weeks)
- def __truediv__(self, other):
- # 假设other是一个整数,表示要将时间间隔分割的份数
- if isinstance(other, int):
- # 使用timedelta的total_seconds方法计算总秒数,然后均分
- total_seconds = self.delta.total_seconds()
- seconds_per_interval = total_seconds / other
- return TimeInterval(seconds=int(seconds_per_interval))
- else:
- raise TypeError("Unsupported operand types for /: 'TimeInterval' and '{}'".format(type(other).__name__))
- def __str__(self):
- return str(self.delta)
- if __name__ == '__main__':
- interval = TimeInterval(hours=2)
- result = interval / 4 # 将2小时均分为4份
- print(result) # 输出类似 0:30:00 的结果,表示每份是30分钟
-
- # 4、分数类(实现两个分数之间的除法)
- from fractions import Fraction
- class MyFraction:
- def __init__(self, numerator, denominator):
- self.numerator = numerator
- self.denominator = denominator
- def __truediv__(self, other):
- # 假设other也是一个MyFraction的实例
- if isinstance(other, MyFraction):
- # 分数除法的规则:a/b ÷ c/d = a/b × d/c
- return MyFraction(self.numerator * other.denominator, self.denominator * other.numerator)
- elif isinstance(other, (int, float)):
- # 分数除以整数或浮点数,可以看作分数乘以整数的倒数或浮点数的倒数
- return MyFraction(self.numerator, self.denominator * other)
- else:
- raise TypeError("Unsupported operand types for /: 'MyFraction' and '{}'".format(type(other).__name__))
- def __str__(self):
- return f"{self.numerator}/{self.denominator}"
- if __name__ == '__main__':
- f1 = MyFraction(1, 2)
- f2 = MyFraction(2, 3)
- result = f1 / f2
- print(result) # 输出:3/4
-
- # 5、图形类(例如,二维图形的面积“除法”)
- class Rectangle:
- def __init__(self, width, height):
- self.width = width
- self.height = height
- def area(self):
- return self.width * self.height
- def __truediv__(self, other_area):
- # 这里假设other_area是一个数值,表示要均分的面积
- # 返回一个Rectangle对象,其面积尽可能接近给定值,但宽度和高度可能不是整数
- return Rectangle(self.width * (self.area() / other_area) ** 0.5,
- self.height * (self.area() / other_area) ** 0.5)
- if __name__ == '__main__':
- rect = Rectangle(4, 6)
- small_rect = rect / 10 # 尝试将矩形面积均分为10份,但结果可能不是完美的矩形
- print(small_rect.width, small_rect.height) # 输出:类似于6.196773353931867 9.2951600308978
-
- # 6、文本处理类(例如,字符串按长度“除法”)
- class TextChunk:
- def __init__(self, text):
- self.text = text
- def __truediv__(self, chunk_size):
- # 这里不是真正的除法,而是将文本按指定大小分割
- chunks = [self.text[i:i + chunk_size] for i in range(0, len(self.text), chunk_size)]
- return chunks
- if __name__ == '__main__':
- text = TextChunk("Hello, world! This is a test.")
- chunks = text / 5 # 将文本每5个字符分割一次
- for chunk in chunks:
- print(chunk)
-
- # 7、自定义数值类型(例如,有理数)
- class Rational:
- def __init__(self, numerator, denominator):
- self.numerator = numerator
- self.denominator = denominator
- def __truediv__(self, other):
- if isinstance(other, Rational):
- return Rational(self.numerator * other.denominator, self.denominator * other.numerator)
- elif isinstance(other, int) or isinstance(other, float):
- return Rational(self.numerator, self.denominator * other)
- def __str__(self):
- return f"{self.numerator}/{self.denominator}"
- if __name__ == '__main__':
- r1 = Rational(1, 2)
- r2 = Rational(1, 3)
- result = r1 / r2
- print(result) # 输出:3/2
-
- # 8、颜色类(支持颜色的“混合”或“亮度调整”)
- class Color:
- def __init__(self, r, g, b):
- self.r = r
- self.g = g
- self.b = b
- def __truediv__(self, factor):
- # 假设factor是一个介于0和1之间的浮点数,用于调整颜色的亮度
- return Color(int(self.r / factor), int(self.g / factor), int(self.b / factor))
- if __name__ == '__main__':
- color = Color(128, 255, 0)
- darker_color = color / 2 # 假设这里的意思是降低亮度,而不是真的除法
- print(darker_color.r, darker_color.g, darker_color.b) # 输出类似 64 127 0 的颜色值
-
- # 9、复数类
- class Complex:
- def __init__(self, real, imag):
- self.real = real
- self.imag = imag
- def __truediv__(self, other):
- if isinstance(other, Complex):
- denominator = other.real ** 2 + other.imag ** 2
- return Complex((self.real * other.real + self.imag * other.imag) / denominator,
- (self.imag * other.real - self.real * other.imag) / denominator)
- else:
- return Complex(self.real / other, self.imag / other)
- if __name__ == '__main__':
- c1 = Complex(1, 2)
- c2 = c1 / 2
- print(c2.real, c2.imag) # 输出 0.5 1.0
-
- # 10、向量类(点乘)
- class Vector:
- def __init__(self, x, y):
- self.x = x
- self.y = y
- def __truediv__(self, scalar):
- return Vector(self.x / scalar, self.y / scalar)
- if __name__ == '__main__':
- v = Vector(2, 4)
- result = v / 2
- print(result.x, result.y) # 输出 1.0 2.0
76、__trunc__方法
76-1、语法
- __trunc__(self, /)
- Truncating an Integral returns itself
76-2、参数
76-2-1、self(必须):一个对实例对象本身的引用,在类的所有方法中都会自动传递。
76-2-2、 /(可选):这是从Python 3.8开始引入的参数注解语法,它表示这个方法不接受任何位置参数(positional-only parameters)之后的关键字参数(keyword arguments)。
76-3、功能
用于定义当对象被int()函数调用时应该返回什么值。
76-4、返回值
返回一个整数,表示对象被截断后的值。
76-5、说明
该方法通常用于实现那些可以被截断为整数的对象,比如浮点数或自定义的数字类型。
76-6、用法
- # 076、__trunc__方法:
- # 1、分数类
- class Fraction:
- def __init__(self, numerator, denominator):
- self.numerator = numerator
- self.denominator = denominator
- def __trunc__(self):
- return self.numerator // (self.denominator or 1)
- if __name__ == '__main__':
- f = Fraction(7, 3)
- print(int(f)) # 输出: 2,因为7/3的整数部分是2
-
- # 2、自定义浮点数类(四舍五入到最接近的整数)
- class RoundedFloat:
- def __init__(self, value):
- self.value = round(value)
- def __trunc__(self):
- return int(self.value)
- if __name__ == '__main__':
- rf = RoundedFloat(3.7)
- print(int(rf)) # 输出: 4
-
- # 3、时间戳类(只取小时部分)
- from datetime import datetime, timedelta
- class Timestamp:
- def __init__(self, dt):
- self.dt = dt
-
- def __trunc__(self):
- return (self.dt - timedelta(minutes=self.dt.minute, seconds=self.dt.second,
- microseconds=self.dt.microsecond)).replace(tzinfo=None)
- if __name__ == '__main__':
- ts = Timestamp(datetime.now())
- print(ts.__trunc__().strftime("%Y-%m-%d %H:%M:%S")) # 输出:类似于2024-06-08 13:00:00
-
- # 4、字符串长度类
- class StringLength:
- def __init__(self, string):
- self.string = string
- def __trunc__(self):
- return len(self.string)
- if __name__ == '__main__':
- length = StringLength("Hello, World!")
- print(int(length)) # 输出: 13
-
- # 5、自定义颜色类(亮度截断)
- class Color:
- def __init__(self, r, g, b):
- self.r = r
- self.g = g
- self.b = b
- def brightness(self):
- return (self.r + self.g + self.b) // 3
- def __trunc__(self):
- return int(self.brightness())
- if __name__ == '__main__':
- color = Color(255, 128, 0)
- print(int(color)) # 输出: 127
-
- # 6、自定义向量类(长度截断)
- import math
- class Vector:
- def __init__(self, x, y):
- self.x = x
- self.y = y
- def length(self):
- return math.sqrt(self.x ** 2 + self.y ** 2)
- def __trunc__(self):
- return int(round(self.length()))
- if __name__ == '__main__':
- vector = Vector(3, 4)
- print(int(vector)) # 输出: 5 (向量的长度,四舍五入到最接近的整数)
-
- # 7、自定义货币类
- class Money:
- def __init__(self, amount, currency='USD'):
- self.amount = amount
- self.currency = currency
- def __trunc__(self):
- return int(self.amount)
- if __name__ == '__main__':
- money = Money(123.45)
- print(int(money)) # 输出: 123 (忽略小数部分)
-
- # 8、自定义价格范围类
- class PriceRange:
- def __init__(self, min_price, max_price):
- self.min_price = min_price
- self.max_price = max_price
- def midpoint(self):
- return (self.min_price + self.max_price) / 2
- def __trunc__(self):
- return int(round(self.midpoint()))
- if __name__ == '__main__':
- price_range = PriceRange(10, 20)
- print(int(price_range)) # 输出: 15 (价格范围的中点,四舍五入到最接近的整数)
-
- # 9、自定义进度条类
- class ProgressBar:
- def __init__(self, total, current=0):
- self.total = total
- self.current = current
- def __str__(self):
- # 这里只是简单示意,实际上可能需要更复杂的逻辑来显示进度条
- return f"[{'#' * (self.current // (self.total // 10))} {' ' * ((self.total // 10) - (self.current // (self.total // 10)))}] {self.current}/{self.total}"
- def __trunc__(self):
- # 假设进度条当前进度可以“截断”为完成的百分比(整数)
- return int((self.current / self.total) * 100)
- if __name__ == '__main__':
- progress = ProgressBar(100, 68)
- print(progress) # 输出类似: [###### ] 68/100
- print(int(progress)) # 输出: 68(假设我们想要的是百分比,但这里仅作为示例)
-
- # 10、自定义评分系统类
- class RatingSystem:
- def __init__(self, score):
- self.score = score
- def __trunc__(self):
- # 假设评分可以“截断”为整数星级(去掉小数部分)
- return int(self.score)
- if __name__ == '__main__':
- rating = RatingSystem(4.7)
- print(int(rating)) # 输出: 4(四星级评价)
-
- # 11、自定义日期范围类
- from datetime import date
- class DateRange:
- def __init__(self, start_date, end_date):
- self.start_date = start_date
- self.end_date = end_date
- def __trunc__(self):
- # 假设我们想要得到日期范围中天数的整数部分(不考虑具体的日期)
- return (self.end_date - self.start_date).days
- if __name__ == '__main__':
- date_range = DateRange(date(2019, 3, 13), date(2024, 6, 8))
- print(int(date_range)) # 输出: 1914(日期范围中的天数)
-
- # 12、自定义物品清单类(库存量截断)
- class InventoryItem:
- def __init__(self, name, quantity):
- self.name = name
- self.quantity = quantity
- def __trunc__(self):
- # 假设我们想要获取库存量的整数部分(不考虑小数,可能是用于某些只能存储整数数量的情况)
- return int(self.quantity)
- if __name__ == '__main__':
- item = InventoryItem("Apple", 10.5) # 假设有10个半苹果是不合理的,所以我们截断为10个
- print(int(item)) # 输出: 10(库存量)
评论记录:
回复评论: