首页 > 解决方案 > 是否有使用特殊类方法访问多维列表的 Pythonic 范例?

问题描述

给定一个dataclass表示 2D 列表的自定义,是否有一种 Pythonic 或特别优雅的方式通过特殊的类方法提供不同的修改方法,即__setitem____getitem__.

例如,假设第一个维度是街道,第二个维度是房屋。您希望能够占领整条街道以及单个房屋。同样,您想要创建整条街道,以及现有街道上的个别房屋。

我知道您可以混合使用默认参数,或者使用类型/长度检查的元组。或者您也可以安全地使用它并具有离散的访问功能。

然而,这似乎也是一个有经典解决方案的问题。谢谢!

使用类型检查的示例:

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

    def __getitem__(self, index):
        if isinstance(index, tuple):
            x, y = index
            return self._data[x][y]
        else:
            return self._data[index]

    def __setitem__(self, index, value):
        if isinstance(index, tuple):
            x, y = index
            self._data[x][y] = value
        else:
            self._data[index] = value

myMDL = multiDimList()
print(myMDL[0])
print(myMDL[0, 0])
myMDL[0] = [9, 10, 11]
print(myMDL[0])
myMDL[0, 0] = 12
print(myMDL[0])

输出:

[0, 1, 2]
0
[9, 10, 11]
[12, 10, 11]

标签: pythonlist

解决方案


你所拥有的是一个开始,但它是不对称的;您可以获取/设置或单个元素,但不能获取/设置。完全对称的情况并不难实现,因为它需要用户的更多合作。

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

    def __getitem__(self, index):
        x, y = index
        if isinstance(x, int):
            return self._data[x][y]
        elif isinstance(x, slice):
            return [row[y] for row in self._data[x]]

    def __setitem__(self, index, value):
        x, y = index
        if isinstance(x, int):
            self._data[x][y] = value
        elif isinstance(x, slice):
            for r, v in zip(self._data[x], value):
                r[y] = v

    def __str__(self):
        return '\n'.join(''.join(map(str, r)) for r in self._data)


d = MultiDimList()

此示例不允许使用表示行的单个整数的快捷方式;您必须指定两个轴。

>>> d[0, :]
[0, 1, 2]
>>> d[:, 0]
[0, 3, 6]
>>> d[0, :] = "abc"
>>> d[:, 0] = "xyz"
>>> d[1,1] = "*"
>>> print(d)
xbc
y*5
z78

如果您想允许单个整数暗示特定行,您可以扩充__getitem____setitem__如下。

def _parse_index(self, index):
    try:
        x, y = index
    except ValueError:
        x = index
        y = slice()
    return x, y

def __getitem__(self, index):
    x, y = self._parse_index(index)
    if isinstance(x, int):
        return self._data[x][y]
    elif isinstance(x, slice):
        return [row[y] for row in self._data[x]]

def __setitem__(self, index, value):
    x, y = self._parse_index(index)
    if isinstance(x, int):
        self._data[x][y] = value
    elif isinstance(x, slice):
        for r, v in zip(self._data[x], value):
            r[y] = v

推荐阅读