本文目录导读:

- 字符串表示:
__str__和__repr__ - 比较操作:
__eq__,__lt__,__gt__等 - 容器行为:
__getitem__,__setitem__,__len__,__contains__ - 迭代器支持:
__iter__和__next__ - 上下文管理器:
__enter__和__exit__ - 运算符重载:
__add__,__sub__,__mul__等 - 属性访问控制:
__getattr__,__setattr__,__getattribute__ - 可调用对象:
__call__ - 完整案例:自定义字典类
在Python中,魔法方法(Magic Methods,也叫双下划线方法)能让我们自定义类的行为,使其更像Python内置类型,下面通过具体案例来说明魔法方法的常见应用场景。
字符串表示:__str__ 和 __repr__
class Book:
def __init__(self, title, author, price):
self.title = title
self.author = author
self.price = price
# 给用户看的友好字符串
def __str__(self):
return f"《{self.title}》- {self.author}"
# 给开发者看的无歧义字符串
def __repr__(self):
return f"Book('{self.title}', '{self.author}', {self.price})"
book = Book("Python编程", "张三", 59.0)
print(str(book)) # 《Python编程》- 张三
print(repr(book)) # Book('Python编程', '张三', 59.0)
比较操作:__eq__, __lt__, __gt__ 等
class Student:
def __init__(self, name, score):
self.name = name
self.score = score
# 定义等于比较
def __eq__(self, other):
return self.score == other.score
# 定义小于比较
def __lt__(self, other):
return self.score < other.score
# 定义字符串表示便于打印
def __repr__(self):
return f"{self.name}: {self.score}"
students = [
Student("小明", 85),
Student("小红", 92),
Student("小刚", 78)
]
students.sort() # 自动使用 __lt__ 排序
print(students) # [小刚: 78, 小明: 85, 小红: 92]
print(students[0] == students[1]) # False,使用 __eq__
容器行为:__getitem__, __setitem__, __len__, __contains__
class Playlist:
def __init__(self):
self._songs = []
# 添加歌曲
def add_song(self, song):
self._songs.append(song)
# 获取长度
def __len__(self):
return len(self._songs)
# 索引访问
def __getitem__(self, index):
return self._songs[index]
# 索引赋值
def __setitem__(self, index, song):
self._songs[index] = song
# 包含检查
def __contains__(self, song):
return song in self._songs
playlist = Playlist()
playlist.add_song("告白气球")
playlist.add_song("七里香")
playlist.add_song("青花瓷")
print(len(playlist)) # 3,使用 __len__
print(playlist[1]) # 七里香,使用 __getitem__
playlist[1] = "稻香" # 使用 __setitem__
print("稻香" in playlist) # True,使用 __contains__
迭代器支持:__iter__ 和 __next__
class CountDown:
def __init__(self, start):
self.current = start
def __iter__(self):
return self
def __next__(self):
if self.current <= 0:
raise StopIteration
self.current -= 1
return self.current + 1
for num in CountDown(5):
print(num, end=" ") # 5 4 3 2 1
上下文管理器:__enter__ 和 __exit__
class FileManager:
def __init__(self, filename, mode='r'):
self.filename = filename
self.mode = mode
def __enter__(self):
self.file = open(self.filename, self.mode)
return self.file
def __exit__(self, exc_type, exc_val, exc_tb):
self.file.close()
# 返回 False 会传播异常,True 会抑制异常
return False
# 使用 with 语句自动管理资源
with FileManager('test.txt', 'w') as f:
f.write('Hello, Python!')
运算符重载:__add__, __sub__, __mul__ 等
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 __mul__(self, scalar):
return Vector(self.x * scalar, self.y * scalar)
def __str__(self):
return f"Vector({self.x}, {self.y})"
v1 = Vector(1, 2)
v2 = Vector(3, 4)
print(v1 + v2) # Vector(4, 6),使用 __add__
print(v1 * 3) # Vector(3, 6),使用 __mul__
属性访问控制:__getattr__, __setattr__, __getattribute__
class Config:
def __init__(self):
self.settings = {
'host': 'localhost',
'port': 8080
}
def __getattr__(self, name):
# 当常规属性查找失败时调用
if name in self.settings:
return self.settings[name]
raise AttributeError(f"Config has no attribute '{name}'")
def __setattr__(self, name, value):
# 拦截所有属性设置
if name == 'settings':
super().__setattr__(name, value)
else:
# 存储到 settings 字典中
if not hasattr(self, 'settings'):
self.settings = {}
self.settings[name] = value
config = Config()
print(config.host) # localhost,通过 __getattr__
config.port = 9090 # 通过 __setattr__ 存储
print(config.port) # 9090
可调用对象:__call__
class Logger:
def __init__(self, prefix):
self.prefix = prefix
def __call__(self, message, level='INFO'):
print(f"[{self.prefix}] [{level}] {message}")
logger = Logger("APP")
logger("应用启动") # [APP] [INFO] 应用启动
logger("错误发生", "ERROR") # [APP] [ERROR] 错误发生
完整案例:自定义字典类
class CaseInsensitiveDict:
"""键大小写不敏感的字典"""
def __init__(self, data=None):
self._data = {}
if data:
for key, value in data.items():
self[key] = value
def __setitem__(self, key, value):
self._data[key.lower()] = value
def __getitem__(self, key):
return self._data[key.lower()]
def __delitem__(self, key):
del self._data[key.lower()]
def __contains__(self, key):
return key.lower() in self._data
def __len__(self):
return len(self._data)
def __iter__(self):
return iter(self._data)
def __repr__(self):
return str(self._data)
# 使用示例
d = CaseInsensitiveDict({"Name": "Alice", "Age": 30})
print(d["NAME"]) # Alice,大小写不敏感
print(d["name"]) # Alice
d["AGE"] = 31 # 覆盖原有的 Age
print("age" in d) # True
print(len(d)) # 2
for key in d:
print(key, d[key]) # name Alice, age 31
魔法方法的应用核心价值:
- 让自定义类更像内置类型 - 支持
len()、in、 等操作 - 实现特定协议 - 迭代器、上下文管理器、数字类型等
- 控制对象行为 - 属性访问、运算符重载、字符串表示
- 简化使用接口 - 通过
__call__使对象可调用,通过__enter__/__exit__支持with语句
你在项目中遇到哪些需要自定义魔法方法的场景吗?我可以帮你分析如何实现。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播