魔法方法(Magic Methods)是Python中一种特殊的方法,它们以双下划线(__
)开头和结尾(如__init__
、__str__
等)。魔法方法允许你定义类在特定情况下的行为,例如初始化、字符串表示、运算符重载等。
__new__(cls, [...])
: 创建实例时调用的第一个方法
__init__(self, [...])
: 实例初始化方法
__del__(self)
: 析构方法,当实例被销毁时调用
__str__(self)
: 定义str()
和print()
的行为
__repr__(self)
: 定义repr()
的行为,通常用于调试
__format__(self, format_spec)
: 定义format()
的行为
__eq__(self, other)
: 定义==
行为
__ne__(self, other)
: 定义!=
行为
__lt__(self, other)
: 定义<
行为
__le__(self, other)
: 定义<=
行为
__gt__(self, other)
: 定义>
行为
__ge__(self, other)
: 定义>=
行为
__add__(self, other)
: +
__sub__(self, other)
: -
__mul__(self, other)
: *
__truediv__(self, other)
: /
__floordiv__(self, other)
: //
__mod__(self, other)
: %
__pow__(self, other)
: **
__len__(self)
: 定义len()
行为
__getitem__(self, key)
: 定义self[key]
行为
__setitem__(self, key, value)
: 定义self[key] = value
行为
__delitem__(self, key)
: 定义del self[key]
行为
__contains__(self, item)
: 定义in
操作符行为
__call__(self, [...])
: 使实例可以像函数一样被调用
__enter__(self)
: 定义with
语句开始时的行为
__exit__(self, exc_type, exc_val, exc_tb)
: 定义with
语句结束时的行为
__init__
- 构造初始化方法这是最常见的魔法方法,用于初始化新创建的对象。
class Dog:
def __init__(self, name, age):
self.name = name # 设置实例属性
self.age = age
print(f"一只名叫{name}的狗出生了!")
# 创建实例时会自动调用__init__
my_dog = Dog("旺财", 3) # 输出:一只名叫旺财的狗出生了!
print(my_dog.name) # 输出:旺财
__str__
vs __repr__
- 字符串表示__str__
:给用户看的友好字符串
__repr__
:给开发者看的准确字符串(通常可以用来重建对象)
class Point:
def __init__(self, x, y):
self.x = x
self.y = y
def __str__(self):
return f"这是一个点({self.x}, {self.y})"
def __repr__(self):
return f"Point({self.x}, {self.y})"
p = Point(1, 2)
print(p) # 输出:这是一个点(1, 2)
print(str(p)) # 输出:这是一个点(1, 2)
print(repr(p)) # 输出:Point(1, 2)
class Vector:
def __init__(self, x, y):
self.x = x
self.y = y
# 加法 +
def __add__(self, other):
return Vector(self.x + other.x, self.y + other.y)
# 减法 -
def __sub__(self, other):
return Vector(self.x - other.x, self.y - other.y)
# 乘法 * (向量与数字相乘)
def __mul__(self, scalar):
return Vector(self.x * scalar, self.y * scalar)
def __str__(self):
return f"Vector({self.x}, {self.y})"
v1 = Vector(2, 3)
v2 = Vector(1, 1)
print(v1 + v2) # Vector(3, 4)
print(v1 - v2) # Vector(1, 2)
print(v1 * 3) # Vector(6, 9)
class Student:
def __init__(self, name, score):
self.name = name
self.score = score
# 等于 ==
def __eq__(self, other):
return self.score == other.score
# 大于 >
def __gt__(self, other):
return self.score > other.score
# 小于等于 <=
def __le__(self, other):
return self.score <= other.score
alice = Student("Alice", 85)
bob = Student("Bob", 75)
print(alice == bob) # False
print(alice > bob) # True
print(alice <= bob) # False
__len__
- 获取长度class Playlist:
def __init__(self, songs):
self.songs = list(songs)
def __len__(self):
return len(self.songs)
my_playlist = Playlist(["Song1", "Song2", "Song3"])
print(len(my_playlist)) # 输出:3
__getitem__
和 __setitem__
- 索引访问class Playlist:
def __init__(self, songs):
self.songs = list(songs)
def __getitem__(self, index):
return self.songs[index]
def __setitem__(self, index, value):
self.songs[index] = value
pl = Playlist(["A", "B", "C"])
print(pl[1]) # 输出:B
pl[1] = "New Song"
print(pl[1]) # 输出:New Song
__iter__
- 使对象可迭代class CountDown:
def __init__(self, start):
self.start = start
def __iter__(self):
current = self.start
while current > 0:
yield current
current -= 1
for num in CountDown(5):
print(num) # 输出:5 4 3 2 1
__call__
- 使实例可调用class Adder:
def __init__(self, n):
self.n = n
def __call__(self, x):
return self.n + x
add5 = Adder(5)
print(add5(3)) # 输出:8
print(add5(10)) # 输出:15
__enter__
和 __exit__
- 上下文管理class Timer:
def __enter__(self):
import time
self.start = time.time()
return self
def __exit__(self, exc_type, exc_val, exc_tb):
import time
self.end = time.time()
print(f"耗时: {self.end - self.start:.2f}秒")
with Timer():
# 模拟耗时操作
sum(i for i in range(1000000))
# 输出:耗时: 0.12秒
class Fraction:
def __init__(self, numerator, denominator=1):
self.numerator = numerator
self.denominator = denominator
self._simplify()
def _simplify(self):
"""约分分数"""
def gcd(a, b):
while b:
a, b = b, a % b
return a
common_divisor = gcd(self.numerator, self.denominator)
self.numerator //= common_divisor
self.denominator //= common_divisor
def __add__(self, other):
new_num = self.numerator * other.denominator + other.numerator * self.denominator
new_den = self.denominator * other.denominator
return Fraction(new_num, new_den)
def __sub__(self, other):
new_num = self.numerator * other.denominator - other.numerator * self.denominator
new_den = self.denominator * other.denominator
return Fraction(new_num, new_den)
def __mul__(self, other):
return Fraction(self.numerator * other.numerator,
self.denominator * other.denominator)
def __truediv__(self, other):
return Fraction(self.numerator * other.denominator,
self.denominator * other.numerator)
def __eq__(self, other):
return (self.numerator == other.numerator and
self.denominator == other.denominator)
def __str__(self):
return f"{self.numerator}/{self.denominator}"
def __repr__(self):
return f"Fraction({self.numerator}, {self.denominator})"
# 使用示例
f1 = Fraction(1, 2)
f2 = Fraction(1, 3)
print(f1 + f2) # 输出:5/6
print(f1 - f2) # 输出:1/6
print(f1 * f2) # 输出:1/6
print(f1 / f2) # 输出:3/2
print(f1 == f2) # 输出:False
核心概念:
魔法方法是Python中特殊的方法,用于自定义类的行为
它们以双下划线开头和结尾
Python在特定情况下自动调用这些方法
主要用途:
初始化对象(__init__
, __new__
)
字符串表示(__str__
, __repr__
)
运算符重载(__add__
, __sub__
等)
容器行为(__len__
, __getitem__
等)
上下文管理(__enter__
, __exit__
)
可调用对象(__call__
)
最佳实践:
__repr__
应该返回一个可以用来重建对象的字符串
__str__
应该返回一个用户友好的字符串
实现比较方法时保持一致性
运算符重载应该保持直观的行为
注意事项:
不要滥用魔法方法,保持行为直观
某些魔法方法需要成对实现(如__eq__
和__hash__
)
继承内置类型时要小心,可能需要重写多个魔法方法
学习建议:
从简单的__init__
和__str__
开始
逐步尝试运算符重载
理解Python的数据模型如何工作
查看内置类型的源代码学习标准实现
魔法方法总结表
魔法方法 | 描述 | 触发方式 |
---|---|---|
__init__(self) |
对象初始化 | obj = Class() |
__str__(self) |
用户友好字符串表示 | str(obj) , print(obj) |
__repr__(self) |
开发者字符串表示 | repr(obj) |
__add__(self, other) |
加法运算 + |
obj1 + obj2 |
__sub__(self, other) |
减法运算 - |
obj1 - obj2 |
__mul__(self, other) |
乘法运算 * |
obj1 * obj2 |
__eq__(self, other) |
等于比较 == |
obj1 == obj2 |
__lt__(self, other) |
小于比较 < |
obj1 < obj2 |
__len__(self) |
获取长度 | len(obj) |
__getitem__(self, key) |
索引访问 | obj[key] |
__setitem__(self, key, value) |
索引赋值 | obj[key] = value |
__iter__(self) |
迭代支持 | for x in obj |
__call__(self, ...) |
使实例可调用 | obj() |
__enter__(self) , __exit__(self) |
上下文管理 | with obj: |
记住这些魔法方法的关键是理解它们何时被Python自动调用。通过实现这些方法,你可以让你自定义的类表现得像Python内置类型一样自然。