刚开始学Python的时候,我总觉得类是个麻烦东西。明明写几个函数就能搞定的事,非要搞个类出来。直到后来遇到一个项目,数据要反复计算、验证、转格式,我才意识到类的好处。而真正让我觉得“这工具太顺手了”的,是那几个魔术方法。它们能让你的类像原生对象一样好用,甚至更好用。
1. __repr__ 和 __str__:看清你的对象
调试代码时最烦的是打印一个对象,出来一串 <__main__.Student object at 0x7f...>。你根本不知道里边有什么。只要加上 __repr__,事情就简单了。
比如我写一个学生类:
class Student:
def __init__(self, name, age):
self.name = name
self.age = age
def __repr__(self):
return f'Student(name='{self.name}', age={self.age})'
s = Student('张三', 18)
print(s) 输出: Student(name='张三', age=18)
这样一来,每次打印对象,你都能直接看到关键信息。这比翻代码找属性名要快得多。而且别人用你的类时,一眼就能看懂数据长什么样。
2. __getitem__ 和 __setitem__:像字典一样操作
有时候你希望对象像字典一样通过键来取值。比如处理一个配置类:
class Config:
def __init__(self):
self._data = {'timeout': 10, 'retry': 3}
def __getitem__(self, key):
return self._data.get(key)
def __setitem__(self, key, value):
self._data[key] = value
cfg = Config()
print(cfg['timeout']) 输出: 10
cfg['retry'] = 5
不用写一堆getter和setter方法,直接用方括号取值赋值。代码读起来更自然,就像操作一个普通字典一样。
3. __call__:让对象能直接调用
有时候你希望对象本身就像一个函数。比如做个缓存类,每次调用时返回缓存的结果:
class Cache:
def __init__(self, func):
self.func = func
self._cache = {}
def __call__(self, args):
if args not in self._cache:
self._cache[args] = self.func(args)
return self._cache[args]
@Cache
def slow_add(a, b):
import time; time.sleep(0.5)
return a + b
print(slow_add(1, 2)) 第一次调用等0.5秒
print(slow_add(1, 2)) 第二次瞬间返回
这比用类方法 or 额外函数要优雅。你把对象当装饰器用,调用方式和普通函数一模一样。
4. __enter__ 和 __exit__:自动清理资源
操作文件、数据库这些资源,最怕忘记关闭。只要实现了上下文管理,就能用 with 语句自动搞定:
class Database:
def __enter__(self):
print('连接数据库')
return self
def __exit__(self, args):
print('关闭连接')
def query(self, sql):
print(f'执行 {sql}')
with Database() as db:
db.query('SELECT FROM users')
运行完自动关闭,你永远不用担心忘记释放资源。代码既安全又干净。
5. __iter__:让对象能循环
如果你的类管理了一组数据,加上 __iter__ 就能直接用 for 循环遍历:
class Team:
def __init__(self, members):
self.members = members
def __iter__(self):
return iter(self.members)
team = Team(['Alice', 'Bob', 'Carol'])
for person in team:
print(person)
这比写个返回列表的方法更符合Python风格。别人拿到你的对象,马上就知道怎么用。
这些魔术方法不是你非得记住的东西。当你觉得某个类用着别扭时,想想能不能用它们改写一下。你写的代码会越来越自然,最终别人读起来会觉得“这像Python原生的东西”。那种感觉,真的挺爽。