You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python重写多维数组setter时嵌套索引赋值不触发的问题

根本原因

Python的嵌套索引赋值是从左向右逐层解析执行的,board[1][1] = 3 等价于以下两步:

  1. 执行 temp = board.__getitem__(1),拿到第一层索引对应的返回值,也就是你代码里的原生Python列表
  2. 执行 temp.__setitem__(1, 3),对第一步返回的原生列表执行赋值操作

你只重写了外层Board类的__setitem__方法,内层返回的原生列表的__setitem__还是Python默认实现,自然不会触发你写的自定义逻辑。而单层赋值board[0] = [1,3,1]是直接调用Board类的__setitem__,所以符合预期。

可行解决方案

下面给出两种常用的实现方案:

方案1:支持多维元组索引

Python的魔法方法__getitem__、__setitem__天然支持接收元组作为索引参数,你可以修改方法逻辑,直接用board[1,1] = 3的形式完成多维赋值,实现成本最低。
修改后的代码示例:

class Board:
    def __init__(self):
        self.board = []
        for k in range(3):
            self.board.append([0] * 3)

    def __str__(self):
        return '\n'.join([' '.join([str(num) for num in row]) for row in self.board])

    def __repr__(self):
        return self.__str__()

    def __setitem__(self, item, value):
        # 索引为元组时按多维处理
        if isinstance(item, tuple):
            x, y = item
            print(f'setting ({x},{y}) = {value}')
            self.board[x][y] = value
            return
        print(f'setting {item=}\t\t{value=}')
        self.board[item] = value

    def __getitem__(self, item):
        if isinstance(item, tuple):
            x, y = item
            print(f'getting ({x},{y})')
            return self.board[x][y]
        print(f'getting {item=}')
        return self.board[item]

测试效果:

>>> board = Board()
>>> board[1,1] = 3
setting (1,1) = 3
>>> print(board[1,1])
getting (1,1)
3
  • 优点:实现简单,没有额外封装开销
  • 缺点:需要调整调用方的索引写法,不兼容原有嵌套[][]的调用形式

方案2:封装内层列表为自定义类

让__getitem__返回的不是原生列表,而是同样重写了__setitem__的自定义行类,兼容原有嵌套[][]的调用形式。
代码示例:

class BoardRow:
    def __init__(self, row_data):
        self.row = row_data

    def __getitem__(self, item):
        print(f'getting row item={item}')
        return self.row[item]

    def __setitem__(self, item, value):
        print(f'setting row item={item}\t\tvalue={value}')
        self.row[item] = value

class Board:
    def __init__(self):
        self.board = []
        for k in range(3):
            # 内层用自定义BoardRow类替代原生列表
            self.board.append(BoardRow([0] * 3))

    def __str__(self):
        return '\n'.join([' '.join([str(num) for num in row.row]) for row in self.board])

    def __repr__(self):
        return self.__str__()

    def __setitem__(self, item, value):
        print(f'setting {item=}\t\t{value=}')
        self.board[item] = value

    def __getitem__(self, item):
        print(f'getting {item=}')
        return self.board[item]

测试效果:

>>> board = Board()
>>> board[1][1] = 3
getting item=1
setting row item=1		value=3
>>> print(board[1][1])
getting item=1
getting row item=1
3
  • 优点:完全兼容原有嵌套索引的调用写法,自定义逻辑可以灵活插入到每一层索引操作中
  • 缺点:需要额外实现自定义行类,维度更高时需要多层封装,实现成本略高

内容的提问来源于stack exchange,提问作者Dikzamen

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.02 10:45:03