引言:让对象行为更自然
在前面的章节中,我们学习了如何创建类、定义方法和实现面向对象的基本特性。但当我们使用Python内置类型时,会发现它们有一些非常自然的行为:我们可以用len()获取列表的长度,用for循环遍历字典的键,用print()输出有意义的对象描述。这些自然的行为是如何实现的呢?
答案就是魔术方法(Magic Methods),也称为特殊方法或双下方法(Dunder Methods)。这些方法以双下划线开头和结尾(如__init__),它们让我们的自定义对象能够像内置类型一样自然地与Python语言特性交互。
在本节中,我们将深入探讨三个最常用的魔术方法:__str__、__len__和__iter__,并通过银行账户管理系统的实战示例展示它们的强大威力。
第一部分:__str__ 和 __repr__ —— 对象的字符串表示
1.1 为什么需要字符串表示?
当我们创建一个自定义对象并尝试打印它时,默认的输出可能不太友好:
class BankAccount:
def __init__(self, account_holder, balance=0):
self.account_holder = account_holder
self.balance = balance
account = BankAccount("Alice", 1000)
print(account) # 输出: <__main__.BankAccount object at 0x7f8c1d3e7d00>
这种默认表示只告诉我们对象的类和内存地址,对于调试和日志记录几乎没有帮助。我们需要一种方式来提供更有意义的字符串表示。
1.2 __str__ 与 __repr__ 的区别
Python提供了两个魔术方法来控制对象的字符串表示:
__str__:返回对象的"非正式"或可读性好的字符串表示,主要用于显示给最终用户__repr__:返回对象的"正式"字符串表示,通常是一个有效的Python表达式,可以用于重新创建该对象
class BankAccount:
def __init__(self, account_holder, balance=0, account_id=None):
self.account_holder = account_holder
self.balance = balance
self.account_id = account_id or f"ACC{
random.randint(100000, 999999)}"
def __str__(self):
return f"账户 {
self.account_id} - {
self.account_holder}: ${
self.balance:.2f}"
def __repr__(self):
return f"BankAccount('{
self.account_holder}', {
self.balance}, '{
self.account_id}')"
# 使用示例
account = BankAccount("Alice", 1000)
print(str(account)) # 输出: 账户 ACC123456 - Alice: $1000.00
print(repr(account)) # 输出: BankAccount('Alice', 1000, 'ACC123456')
1.3 最佳实践
- 总是实现
__repr__,因为它是最低要求(当__str__未定义时,会回退到使用__repr__) __repr__应该尽可能返回一个能重新创建对象的表达式__str__应该提供对人类友好的输出- 在交互式环境中输入变量名时,会调用
__repr__
第二部分:__len__ —— 定义对象的长度
2.1 为什么需要定义长度?
len()是Python中最常用的内置函数之一,它可以用于列表、字典、字符串等内置类型。通过实现__len__方法,我们可以让自定义对象也支持这个操作。
2.2 实现__len__方法
在我们的银行账户示例中,可以有多种方式定义"长度":
class BankAccount:
def __init__(self, account_holder, balance=0):
self.account_holder = account_holder
self.balance = balance
self.transactions = [] # 交易记录列表
def deposit(self, amount):
self.balance += amount
self.transactions.append(('deposit', amount))
def withdraw(self, amount):
if amount <= self.balance:
self.balance -= amount
self.transactions.append(('withdraw', amount))
return True
return False
def __len__(self):
# 定义账户的"长度"为交易次数
return len(self.transactions)
def __str__(self):
return f"{
self.account_holder}'s Account: ${
self.balance:.2f}"
# 使用示例
account = BankAccount("Bob", 500)
account.deposit(200)
account.withdraw(100)
account

最低0.47元/天 解锁文章
541

被折叠的 条评论
为什么被折叠?



