Python 特殊方法
在Python的面向对象编程中,特殊方法(也称为魔术方法或双下方法)是以双下划线开头和结尾的方法,例如 __init__
、__str__
等。它们赋予了类特殊的能力,让我们能够自定义对象的行为,使其与Python的内置函数和操作符无缝集成。
什么是特殊方法?
特殊方法是Python解释器调用的内置方法,允许我们定义类实例在特定情况下的行为。当我们使用特定的语法或内置函数时,Python会自动调用这些方法。
提示
特殊方法的命名遵循一个模式:两个下划线 + 方法名 + 两个下划线,例如 __init__
。这种命名方式也是为什么它们被俗称为"双下方法"或"dunder方法"(double underscore)。
常用特殊方法一览
初始化与构造
__init__(self, ...)
: 初始化一个新创建的实例__new__(cls, ...)
: 创建类的新实例(在__init__
之前调用)__del__(self)
: 当对象被垃圾回收时调用
字符串表示
__str__(self)
: 定义str()
函数的行为__repr__(self)
: 定义repr()
函数的行为
比较操作
__eq__(self, other)
: 定义等于操作符==
的行为__ne__(self, other)
: 定义不等于操作符!=
的行为__lt__(self, other)
: 定义小于操作符<
的行为__gt__(self, other)
: 定义大于操作符>
的行为__le__(self, other)
: 定义小于等于操作符<=
的行为__ge__(self, other)
: 定义大于等于操作符>=
的行为
数值运算
__add__(self, other)
: 定义加法操作符+
的行为__sub__(self, other)
: 定义减法操作符-
的行为__mul__(self, other)
: 定义乘法操作符*
的行为__truediv__(self, other)
: 定义除法操作符/
的行为
容器方法
__len__(self)
: 定义len()
函数的行为__getitem__(self, key)
: 定义通过索引访问元素的行为,如obj[key]
__setitem__(self, key, value)
: 定义通过索引设置元素的行为,如obj[key] = value
__contains__(self, item)
: 定义in
操作符的行为
详细讲解常用特殊方法
__init__
方法
__init__
是最常用的特殊方法之一,用于初始化新创建的对象。
python
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
# 创建Person类的实例
person = Person("张三", 25)
print(f"姓名: {person.name}, 年龄: {person.age}")
输出:
姓名: 张三, 年龄: 25
__str__
和 __repr__
方法
这两个方法都用于返回对象的字符串表示,但用途略有不同:
__str__
用于返回对象的"非正式"字符串表示,主要面向用户__repr__
用于返回对象的"正式"字符串表示,主要面向开发者
python
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
def __str__(self):
return f"{self.name}, {self.age}岁"
def __repr__(self):
return f"Person('{self.name}', {self.age})"
person = Person("张三", 25)
print(str(person)) # 调用 __str__
print(repr(person)) # 调用 __repr__
输出:
张三, 25岁
Person('张三', 25)
备注
当我们直接在交互式解释器中输入变量名并按回车,或使用 print()
函数但没有显式调用 str()
或 repr()
时,Python会首先尝试调用 __str__
。如果没有定义 __str__
,则会回退到 __repr__
。
比较方法
通过定义比较方法,我们可以自定义对象之间如何进行比较操作:
python
class Score:
def __init__(self, value):
self.value = value
def __eq__(self, other):
return self.value == other.value
def __gt__(self, other):
return self.value > other.value
score1 = Score(85)
score2 = Score(90)
score3 = Score(85)
print(f"score1 == score3: {score1 == score3}") # 调用 __eq__
print(f"score1 > score2: {score1 > score2}") # 调用 __gt__
print(f"score1 < score2: {score1 < score2}") # Python 自动推断
输出:
score1 == score3: True
score1 > score2: False
score1 < score2: True
算术运算方法
我们可以重载算术运算符,让自定义对象支持各种数学运算:
python
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 __str__(self):
return f"Vector({self.x}, {self.y})"
v1 = Vector(2, 3)
v2 = Vector(3, 4)
v3 = v1 + v2 # 调用 __add__
print(f"v1 = {v1}")
print(f"v2 = {v2}")
print(f"v1 + v2 = {v3}")
输出:
v1 = Vector(2, 3)
v2 = Vector(3, 4)
v1 + v2 = Vector(5, 7)
容器方法
通过实现以下方法,我们可以使类的实例表现得像一个容器:
python
class MyList:
def __init__(self, data):
self.data = data
def __len__(self):
return len(self.data)
def __getitem__(self, index):
return self.data[index]
def __setitem__(self, index, value):
self.data[index] = value
def __contains__(self, item):
return item in self.data
my_list = MyList([1, 2, 3, 4, 5])
print(f"长度: {len(my_list)}") # 调用 __len__
print(f"第三个元素: {my_list[2]}") # 调用 __getitem__
my_list[1] = 20 # 调用 __setitem__
print(f"修改后的列表: {[my_list[i] for i in range(len(my_list))]}")
print(f"3在列表中: {3 in my_list}") # 调用 __contains__
输出:
长度: 5
第三个元素: 3
修改后的列表: [1, 20, 3, 4, 5]
3在列表中: True
实际应用案例
案例1:创建一个自定义复数类
python
class ComplexNumber:
def __init__(self, real, imag):
self.real = real
self.imag = imag
def __add__(self, other):
return ComplexNumber(self.real + other.real, self.imag + other.imag)
def __sub__(self, other):
return ComplexNumber(self.real - other.real, self.imag - other.imag)
def __mul__(self, other):
# (a+bi)(c+di) = (ac-bd) + (ad+bc)i
real = self.real * other.real - self.imag * other.imag
imag = self.real * other.imag + self.imag * other.real
return ComplexNumber(real, imag)
def __str__(self):
if self.imag >= 0:
return f"{self.real} + {self.imag}i"
else:
return f"{self.real} - {abs(self.imag)}i"
# 创建两个复数
c1 = ComplexNumber(2, 3)
c2 = ComplexNumber(1, -1)
print(f"c1 = {c1}")
print(f"c2 = {c2}")
print(f"c1 + c2 = {c1 + c2}")
print(f"c1 - c2 = {c1 - c2}")
print(f"c1 * c2 = {c1 * c2}")
输出:
c1 = 2 + 3i
c2 = 1 - 1i
c1 + c2 = 3 + 2i
c1 - c2 = 1 + 4i
c1 * c2 = 5 + 1i
案例2:自定义日期类与比较
python
class Date:
def __init__(self, year, month, day):
self.year = year
self.month = month
self.day = day
def __str__(self):
return f"{self.year}-{self.month:02d}-{self.day:02d}"
def __lt__(self, other):
if self.year != other.year:
return self.year < other.year
if self.month != other.month:
return self.month < other.month
return self.day < other.day
def __eq__(self, other):
return self.year == other.year and self.month == other.month and self.day == other.day
# 创建日期对象
date1 = Date(2023, 10, 15)
date2 = Date(2023, 11, 1)
date3 = Date(2023, 10, 15)
print(f"date1: {date1}")
print(f"date2: {date2}")
print(f"date3: {date3}")
print(f"date1 < date2: {date1 < date2}")
print(f"date1 == date3: {date1 == date3}")
输出:
date1: 2023-10-15
date2: 2023-11-01
date3: 2023-10-15
date1 < date2: True
date1 == date3: True
案例3:自定义可迭代对象
python
class Fibonacci:
"""生成斐波那契数列的可迭代类"""
def __init__(self, limit):
self.limit = limit
self.a, self.b = 0, 1
self.count = 0
def __iter__(self):
# 迭代器就是对象本身
self.a, self.b = 0, 1
self.count = 0
return self
def __next__(self):
if self.count >= self.limit:
# 停止迭代
raise StopIteration
result = self.a
self.a, self.b = self.b, self.a + self.b
self.count += 1
return result
# 使用for循环迭代Fibonacci对象
fib = Fibonacci(10)
print("斐波那契数列的前10项:")
for num in fib:
print(num, end=" ")
输出:
斐波那契数列的前10项:
0 1 1 2 3 5 8 13 21 34
总结
Python的特殊方法是面向对象编程中非常强大的工具,它们使我们能够:
- 自定义对象的行为,使其像内置类型一样工作
- 重载运算符,使我们可以用自然的语法操作自定义对象
- 与Python内置函数集成,例如
len()
,str()
,repr()
等
掌握特殊方法,让我们能够写出更加"Pythonic"的代码,充分利用Python的语言特性。特殊方法的设计展现了Python的优雅哲学:通过一致的接口设计,使代码既直观又富有表现力。
练习
- 创建一个
BankAccount
类,实现__add__
、__sub__
方法使其支持账户间的转账操作。 - 实现一个
Temperature
类,支持摄氏度和华氏度之间的转换,并实现特殊方法使其支持比较操作。 - 创建一个
Matrix
类,实现矩阵的加法、减法和乘法运算。 - 实现一个自定义的
Stack
类,使用特殊方法让它支持len()
、索引访问等操作。
进一步阅读
- Python官方文档中关于特殊方法名称的详细说明
- 《流畅的Python》(Fluent Python) 书中对特殊方法有非常深入的讲解
- Python数据模型官方文档