python中的魔法函数(magic methods),也称为双下划线方法(dunder methods),是python面向对象编程的核心机制之一。它们以__开头和结尾,允许我们自定义类的行为,使其更符合python的惯用风格。本文将全面介绍这些魔法函数,助你写出更pythonic的代码。
什么是魔法函数
魔法函数是python中一类特殊的方法,它们允许你:
- 自定义类的内置行为
- 与python内置函数/操作符交互
- 实现协议(如迭代器、上下文管理器等)
“python的魔法函数是其数据模型的核心,它们是框架和python交互的方式。” - guido van rossum
常用魔法函数分类与功能
基础魔法函数
| 方法名 | 功能描述 | 示例 |
|---|---|---|
| __init__ | 构造函数,初始化对象 | obj = myclass() |
| __str__ | 返回用户友好的字符串表示 | print(obj) |
| __repr__ | 返回开发者友好的字符串表示 | repr(obj) |
| __len__ | 返回容器长度 | len(obj) |
class book:
def __init__(self, title, author, pages):
self.title = title
self.author = author
self.pages = pages
def __str__(self):
return f"'{self.title}' by {self.author}"
def __repr__(self):
return f"book(title='{self.title}', author='{self.author}')"
def __len__(self):
return self.pages
book = book("python crash course", "eric matthes", 544)
print(book) # 'python crash course' by eric matthes
print(repr(book)) # book(title='python crash course', author='eric matthes')
print(len(book)) # 544
比较操作魔法函数

这些方法让你的对象可以使用比较操作符:
class box:
def __init__(self, weight):
self.weight = weight
def __lt__(self, other):
return self.weight < other.weight
def __eq__(self, other):
return self.weight == other.weight
box1 = box(10)
box2 = box(20)
print(box1 < box2) # true
print(box1 == box2) # false
算术操作魔法函数
| 方法 | 对应操作符 |
|---|---|
| __add__ | + |
| __sub__ | - |
| __mul__ | * |
| __truediv__ | / |
| __pow__ | ** |
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(1, 2)
v2 = vector(3, 4)
print(v1 + v2) # vector(4, 6)
迭代器与容器协议
迭代器魔法函数

class countdown:
def __init__(self, start):
self.start = start
def __iter__(self):
return self
def __next__(self):
if self.start <= 0:
raise stopiteration
self.start -= 1
return self.start + 1
for i in countdown(5):
print(i, end=' ') # 5 4 3 2 1
容器魔法函数
| 方法 | 功能 |
|---|---|
| __getitem__ | 获取元素 (obj[key]) |
| __setitem__ | 设置元素 (obj[key] = value) |
| __delitem__ | 删除元素 (del obj[key]) |
| __contains__ | 成员检查 (key in obj) |
class sparselist:
def __init__(self, size):
self.size = size
self.data = {}
def __getitem__(self, index):
if index < 0 or index >= self.size:
raise indexerror("index out of range")
return self.data.get(index, 0)
def __setitem__(self, index, value):
if index < 0 or index >= self.size:
raise indexerror("index out of range")
self.data[index] = value
def __contains__(self, value):
return value in self.data.values()
sparse = sparselist(10)
sparse[3] = 42
print(sparse[3]) # 42
print(42 in sparse) # true
print(sparse[4]) # 0
高级魔法函数应用
属性访问控制
class protectedattributes:
def __init__(self):
self._protected = "this is protected"
def __getattr__(self, name):
return f"'{name}' attribute not found"
def __setattr__(self, name, value):
if name.startswith('_'):
super().__setattr__(name, value)
else:
raise attributeerror(f"cannot set attribute '{name}'")
obj = protectedattributes()
print(obj.nonexistent) # 'nonexistent' attribute not found
# obj.public = "test" # raises attributeerror
上下文管理器

class databaseconnection:
def __enter__(self):
print("connecting to database...")
return self
def __exit__(self, exc_type, exc_val, exc_tb):
print("closing connection...")
if exc_type:
print(f"error occurred: {exc_val}")
return true # suppress exceptions
with databaseconnection() as conn:
print("executing query...")
# raise valueerror("invalid sql") # would be handled by __exit__
可调用对象
class counter:
def __init__(self):
self.count = 0
def __call__(self, increment=1):
self.count += increment
return self.count
counter = counter()
print(counter()) # 1
print(counter(5)) # 6
性能优化案例
使用__slots__减少内存占用
class regularpoint:
def __init__(self, x, y):
self.x = x
self.y = y
class slottedpoint:
__slots__ = ['x', 'y']
def __init__(self, x, y):
self.x = x
self.y = y
import sys
regular = regularpoint(1, 2)
slotted = slottedpoint(1, 2)
print(sys.getsizeof(regular)) # 56 bytes (approx)
print(sys.getsizeof(slotted)) # 32 bytes (approx)
性能提示:__slots__可以显著减少大量实例的内存使用,但会限制动态属性添加【1†source】。
实际应用场景
1. 实现自定义数值类型
class fraction:
def __init__(self, numerator, denominator):
self.numerator = numerator
self.denominator = denominator
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 __str__(self):
return f"{self.numerator}/{self.denominator}"
f1 = fraction(1, 2)
f2 = fraction(1, 3)
print(f1 + f2) # 5/6
2. 构建智能代理对象
class lazyproperty:
def __init__(self, func):
self.func = func
self.name = func.__name__
def __get__(self, obj, type=none):
if obj is none:
return self
value = self.func(obj)
setattr(obj, self.name, value)
return value
class circle:
def __init__(self, radius):
self.radius = radius
@lazyproperty
def area(self):
print("computing area...")
return 3.14 * self.radius ** 2
c = circle(5)
print(c.area) # first call: computes and caches
print(c.area) # subsequent call: returns cached value
最佳实践与建议
- 一致性原则:实现比较方法时,确保
__eq__和__hash__一致【2†source】 - 文档字符串:为魔法函数提供清晰的文档说明
- 错误处理:在魔法函数中提供有意义的错误信息
- 性能考虑:对于性能关键代码,考虑使用
__slots__或c扩展 - 协议完整性:实现协议时,确保所有必要方法都已实现
# 好的实践示例
class goodexample:
"""遵循最佳实践的类实现"""
def __init__(self, value):
self._value = value
def __repr__(self):
return f"{self.__class__.__name__}({self._value!r})"
def __str__(self):
return f"value: {self._value}"
def __eq__(self, other):
if not isinstance(other, goodexample):
return notimplemented
return self._value == other._value
def __hash__(self):
return hash(self._value)
总结
python的魔法函数提供了一套强大的工具,让我们能够:
- 自定义对象行为
- 与python内置机制无缝集成
- 编写更直观、pythonic的代码
- 构建高性能、可维护的系统
掌握魔法函数是每个python开发者从初级走向高级的必经之路。它们不仅仅是语法糖,更是python数据模型的核心实现机制。
“简单比复杂更好,但复杂比混乱更好。” - tim peters
通过合理使用魔法函数,我们可以在保持代码简洁的同时,实现复杂而优雅的功能
到此这篇关于一文浅析python中常用的魔法函数使用指南的文章就介绍到这了,更多相关python魔法函数内容请搜索代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持代码网!
发表评论