为什么多个列表索引可以用于__getitem__但不能用于__setitem__

1 投票
3 回答
1596 浏览
提问于 2025-06-18 04:08

考虑以下代码:

class multiDimList1(object):
    def __init__(self):
        self.data = [[[0, 1, 2], [3, 4, 5], [6, 7, 8]],
                    [[0, 1, 2], [3, 4, 5], [6, 7, 8]]]

    def __getitem__(self, index):
        print("MDL1 getitem")
        return self.data[index]

    def __setitem__(self, index, value):
        print("MDL1 setitem")
        index, row, col = index
        self.data[index][row][col] = value

    def __str__(self):
        return ','.join(str(e) for e in self.data)

class multiDimList2(object):
    def __init__(self):
        self.data = [[[0, 1, 2], [3, 4, 5], [6, 7, 8]],
                    [[0, 1, 2], [3, 4, 5], [6, 7, 8]]]

    def __getitem__(self, index):
        print("MDL2 getitem")
        return self.data[index]

    def __setitem__(self, index, value):
        print("MDL2 getitem")
        index, row, col = index
        self.data[index][row][col] = value

    def __str__(self):
        return ','.join(str(e) for e in self.data)

myMDL1 = multiDimList1()
myMDL2 = multiDimList2()

myMDL1[0, 0, 0] = 12
print(myMDL1)

myMDL2[0][0][0] = 12
print(myMDL2)

输出:

MDL1 setitem
[[12, 1, 2], [3, 4, 5], [6, 7, 8]],[[0, 1, 2], [3, 4, 5], [6, 7, 8]]
MDL2 getitem
[[12, 1, 2], [3, 4, 5], [6, 7, 8]],[[0, 1, 2], [3, 4, 5], [6, 7, 8]]

为什么我可以使用 myMDL2[0][0][0] 来获取值,而 __getitem__ 能正确处理这个操作,但当我尝试给这个索引赋值时却没有调用 __setitem__ 呢?

myMDL2[0][0][0] = 12 其实是通过 __getitem__ 创建了一个对正确索引的引用,然后以这种方式设置值。这就意味着我在 __setitem__ 中想要执行的任何其他代码都不会被调用。

相关问题:

  • 暂无相关问题
暂无标签

3 个回答

0

另一方面,如果你想要能够这样做:

myMDL2[0][0][0] = 12

你甚至不需要实现 __setitem__ 这个方法,因为 myMDL2[0] 会返回第一个子列表,而 myMDL2[0][0] 会返回 myMDL2[0] 的第一个子列表,然后 myMDL2[0][0][0] = 12 这行代码会调用 myMDL2[0][0] 返回的列表的 __setitem__ 方法。

2

你的 __getitem__ 方法只是返回了第一层的子列表,所以你可以继续使用下标来访问第二层的子列表,依此类推,因为返回的列表有自己的 __getitem__ 实现。

而你的 __setitem__ 方法则期望接收一个包含三个元素的元组,所以你应该把这个三元组传给 __setitem__

myMDL2[0, 0, 0] = 12 # instead of myMDL2[0][0][0] = 12
3

这是因为

myMDL1[0, 0, 0] = 12

等同于

myMDL1.__setitem__(index=(0,0,0), value=12)

不过,

myMDL2[0][0][0] = 12

等同于

myMDL2.__getitem__(index=0)[0][0] = 12

这意味着首先要完成 myMDL2[0],我们获取它的第一个项目,最后我们把这个项目的值设置为12。

myMDL2[0][0][0] = 12
=> myMDL2.__getitem__(index=0)[0][0] = 12
=> [[0, 1, 2], [3, 4, 5], [6, 7, 8]][0][0] = 12
=> [[0, 1, 2], [3, 4, 5], [6, 7, 8]].__getitem__(index=0)[0] = 12
=> [0, 1, 2][0] = 12
=> [0, 1, 2].__setitem__(index=0, value=12)
=> [12, 1, 2]

不太确定我是否解释清楚了,__setitem__ 并没有在你的 multiDimList2 上被调用。

撰写回答