前言
大家好,我是 倔强青铜三 。欢迎关注我,微信公众号:倔强青铜三。欢迎点赞、收藏、关注,一键三连!
欢迎来到 苦练Python第55天!
今天我们来学习「容器协议」配套的七个魔术方法。掌握它们,你的自定义对象就能像 list、dict 一样被 len()
、for ... in ...
、item in obj
、obj[...]
等语法糖直接调用。
📏 1. __len__
------ 回答"我有多长?"
触发时机
- 内置函数
len(obj)
- 某些需要布尔判断的场景(空容器会被当作 False)
作用
返回一个非负整数,表示容器内元素个数。
示例
python
class MyBox:
def __init__(self, *items):
self._items = list(items)
def __len__(self):
return len(self._items)
box = MyBox("apple", "banana")
print(len(box)) # 2
if box: # 自动调用 __len__
print("非空盒子")
🔍 2. __getitem__
------ 按下标或键取值
触发时机
obj[key]
- 切片
obj[start:stop:step]
for i in obj:
实际先尝试__iter__
,若不存在则退回到 0,1,2... 的__getitem__
作用
返回与 key 对应的值;不存在时抛 KeyError
(字典语义)或 IndexError
(序列语义)。
示例
python
class MyBox:
...
def __getitem__(self, key):
return self._items[key] # 支持切片、负数索引
print(box[0]) # apple
print(box[-1]) # banana
print(box[::-1]) # ['banana', 'apple']
✏️ 3. __setitem__
------ 按下标或键赋值
触发时机
obj[key] = value
作用
把 value 存到指定位置;越界时抛 IndexError
,键不存在时可选择自动添加(字典语义)。
示例
python
class MyBox:
...
def __setitem__(self, key, value):
self._items[key] = value
box[1] = "pear"
print(box[:]) # ['apple', 'pear']
🗑️ 4. __delitem__
------ 按下标或键删除
触发时机
del obj[key]
作用
移除对应元素;不存在抛异常。
示例
python
class MyBox:
...
def __delitem__(self, key):
del self._items[key]
del box[0]
print(len(box)) # 1
🔎 5. __contains__
------ 回答"我在里面吗?"
触发时机
item in obj
item not in obj
作用
返回布尔值;若未定义,Python 退而使用线性扫描的 __iter__
+ 等值比较,效率低。
示例
python
class MyBox:
...
def __contains__(self, item):
return item in self._items
print("pear" in box) # True
🔄 6. __iter__
------ 交出迭代器
触发时机
for element in obj:
list(obj)
、tuple(obj)
、sum(obj)
等需要迭代的地方
作用
返回一个迭代器(对象本身或新迭代器皆可)。若类里没写,Python 会尝试用 0,1,2... 的 __getitem__
兜底。
示例
python
class MyBox:
...
def __iter__(self):
return iter(self._items) # 复用 list 的迭代器
for fruit in box:
print(fruit) # pear
🔁 7. __reversed__
------ 反向迭代
触发时机
reversed(obj)
for x in reversed(obj):
作用
返回一个反向迭代器;若未定义,Python 退而使用 __len__
+ __getitem__
倒序访问,效率差。
示例
python
class MyBox:
...
def __reversed__(self):
return reversed(self._items)
print(list(reversed(box))) # ['pear']
🧪 实战演练:打造一个小型书架
把上面七个方法一次性用齐,实现一个能用 len()
、for
、in
、[]
、del
、reversed()
的迷你书架。
python
class Bookshelf:
def __init__(self):
self._books = []
def add(self, book):
self._books.append(book)
# 1. 长度
def __len__(self):
return len(self._books)
# 2. 取值
def __getitem__(self, index):
return self._books[index]
# 3. 赋值
def __setitem__(self, index, book):
self._books[index] = book
# 4. 删除
def __delitem__(self, index):
del self._books[index]
# 5. 包含
def __contains__(self, book):
return book in self._books
# 6. 正向迭代
def __iter__(self):
return iter(self._books)
# 7. 反向迭代
def __reversed__(self):
return reversed(self._books)
# 使用
shelf = Bookshelf()
shelf.add("Python入门")
shelf.add("流畅的Python")
print(len(shelf)) # 2
print("Python入门" in shelf) # True
print(shelf[1]) # 流畅的Python
shelf[0] = "Python核心编程"
del shelf[1]
for book in shelf:
print(book) # Python核心编程
for book in reversed(shelf):
print(book) # Python核心编程
📌 小结 & 记忆口诀
__len__
说长度__getitem__
拿东西__setitem__
改东西__delitem__
扔东西__contains__
查东西__iter__
顺东西__reversed__
倒东西
把这七个魔术方法写全,你的自定义类就能无缝融入 Python 的容器语法生态,记得把今天的代码敲三遍。
最后感谢阅读!欢迎关注我,微信公众号 :
倔强青铜三
。一键三连(点赞、收藏、关注)!