Python零基础入门:魔法方法详解_python魔法方法
一、什么是魔法方法?
魔法方法(Magic Methods)是Python中一种特殊的方法,它们以双下划线(__
)开头和结尾(如__init__
、__str__
等)。魔法方法允许你定义类在特定情况下的行为,例如初始化、字符串表示、运算符重载等。
二、常见的魔法方法分类
1. 构造和初始化
-
__new__(cls, [...])
: 创建实例时调用的第一个方法 -
__init__(self, [...])
: 实例初始化方法 -
__del__(self)
: 析构方法,当实例被销毁时调用
2. 字符串表示
-
__str__(self)
: 定义str()
和print()
的行为 -
__repr__(self)
: 定义repr()
的行为,通常用于调试 -
__format__(self, format_spec)
: 定义format()
的行为
3. 比较运算符
-
__eq__(self, other)
: 定义==
行为 -
__ne__(self, other)
: 定义!=
行为 -
__lt__(self, other)
: 定义<
行为 -
__le__(self, other)
: 定义<=
行为 -
__gt__(self, other)
: 定义>
行为 -
__ge__(self, other)
: 定义>=
行为
4. 算术运算符
-
__add__(self, other)
:+
-
__sub__(self, other)
:-
-
__mul__(self, other)
:*
-
__truediv__(self, other)
:/
-
__floordiv__(self, other)
://
-
__mod__(self, other)
:%
-
__pow__(self, other)
:**
5. 容器类型方法
-
__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
操作符行为
6. 可调用对象
-
__call__(self, [...])
: 使实例可以像函数一样被调用
7. 上下文管理
-
__enter__(self)
: 定义with
语句开始时的行为 -
__exit__(self, exc_type, exc_val, exc_tb)
: 定义with
语句结束时的行为
三、魔法方法练习题
1. __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) # 输出:旺财
2. __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)
3. 算术运算符
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)
4. 比较运算符
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 bob) # Trueprint(alice <= bob) # False
5. __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
6. __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] = valuepl = Playlist([\"A\", \"B\", \"C\"])print(pl[1]) # 输出:Bpl[1] = \"New Song\"print(pl[1]) # 输出:New Song
7. __iter__
- 使对象可迭代
class CountDown: def __init__(self, start): self.start = start def __iter__(self): current = self.start while current > 0: yield current current -= 1for num in CountDown(5): print(num) # 输出:5 4 3 2 1
8. __call__
- 使实例可调用
class Adder: def __init__(self, n): self.n = n def __call__(self, x): return self.n + xadd5 = Adder(5)print(add5(3)) # 输出:8print(add5(10)) # 输出:15
9. __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/6print(f1 - f2) # 输出:1/6print(f1 * f2) # 输出:1/6print(f1 / f2) # 输出:3/2print(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内置类型一样自然。