如何在Python中通过子类化tuple实现无限重复序列?
解决无限循环桥牌局况序列的实现问题
原代码的问题分析
- 继承tuple的误区:tuple是不可变序列,其内部实现依赖固定长度数组,继承后自定义的
__getitem__不会覆盖原生行为,实例化后本质仍是普通tuple。 - __new__方法调用错误:
tuple.__new__(*DEALVUL)参数格式错误,正确写法应为tuple.__new__(cls, DEALVUL),但即使修正,生成的仍是普通tuple,无法使用自定义逻辑。 - 无限递归问题:
__getitem__中self[board_number % 16]会递归调用自身,导致栈溢出。 - 迭代器实现错误:
__iter__返回iter(self)会使用tuple的有限迭代器,__next__定义在序列类上不符合迭代器协议,无法实现无限循环迭代。
正确实现方案:基于Sequence抽象基类
通过实现collections.abc.Sequence抽象基类,可快速获得序列核心特性(切片、in操作、count/index方法等),同时自定义循环逻辑:
from collections.abc import Sequence class BoardInfo: """示例:存储桥牌局况信息的类""" def __init__(self, board_id, dealer, vulnerability): self.board_id = board_id self.dealer = dealer self.vulnerability = vulnerability def __repr__(self): return f"BoardInfo(board={self.board_id}, dealer={self.dealer}, vul={self.vulnerability})" # 初始化基础序列:对应0-15副牌的局况 DEALVUL = [ BoardInfo(0, 'N', 'None'), BoardInfo(1, 'E', 'NS'), BoardInfo(2, 'S', 'EW'), BoardInfo(3, 'W', 'Both'), BoardInfo(4, 'N', 'NS'), BoardInfo(5, 'E', 'EW'), BoardInfo(6, 'S', 'Both'), BoardInfo(7, 'W', 'None'), BoardInfo(8, 'N', 'EW'), BoardInfo(9, 'E', 'Both'), BoardInfo(10, 'S', 'None'), BoardInfo(11, 'W', 'NS'), BoardInfo(12, 'N', 'Both'), BoardInfo(13, 'E', 'None'), BoardInfo(14, 'S', 'NS'), BoardInfo(15, 'W', 'EW'), ] class BoardInfoSequence(Sequence): """无限循环的桥牌局况序列,兼容tuple核心特性""" def __init__(self, base_seq): self.base = base_seq self.cycle_len = len(base_seq) if self.cycle_len == 0: raise ValueError("Base sequence cannot be empty") def __getitem__(self, key): if isinstance(key, int): # 处理整数索引,支持正负索引 idx = key % self.cycle_len return self.base[idx] elif isinstance(key, slice): # 处理切片,生成对应长度的不可变tuple # 用float('inf')作为切片的默认终止位置,适配无限序列 start, stop, step = key.indices(float('inf')) result = [] current = start while current < stop: result.append(self[current]) current += step if step is not None else 1 return tuple(result) else: raise TypeError(f"Invalid index type: {type(key).__name__}") def __len__(self): # 返回足够大的数值适配实际使用场景(用户提到很少超过36次) return 128 def __iter__(self): # 实现无限循环迭代器 while True: yield from self.base # 实例化序列 board_info = BoardInfoSequence(DEALVUL)
使用示例
- 访问任意索引:
# 第17副牌(对应第1副) print(board_info[16]) # 输出: BoardInfo(board=0, dealer=N, vul=None) print(board_info[17]) # 输出: BoardInfo(board=1, dealer=E, vul=NS) # 第129副牌:129 % 16 = 1 → 对应第1副 print(board_info[129]) # 输出: BoardInfo(board=1, dealer=E, vul=NS)
- 切片操作:
# 获取第15到22副牌(共7副) slice_result = board_info[15:22] print(slice_result) # 输出: ( # BoardInfo(board=15, dealer=W, vul=EW), # BoardInfo(board=0, dealer=N, vul=None), # BoardInfo(board=1, dealer=E, vul=NS), # BoardInfo(board=2, dealer=S, vul=EW), # BoardInfo(board=3, dealer=W, vul=Both), # BoardInfo(board=4, dealer=N, vul=NS), # BoardInfo(board=5, dealer=E, vul=EW) # )
- 无限迭代:
from itertools import islice # 迭代前20副牌 for board in islice(board_info, 0, 20): print(board.board_id) # 输出: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 0 1 2 3
关键特性说明
- 不可变性:切片返回
tuple,保证序列的不可变特性,符合用户对tuple特性的需求。 - 兼容性:继承
Sequence后自动支持in、count()、index()等序列方法。 - 性能:基础序列仅存储一次,所有索引/切片操作均基于模运算获取元素,内存占用低。
内容的提问来源于stack exchange,提问作者Mycroft
相关产品推荐
相关产品推荐

