【问题标题】:Treat a single element list as a scalar in Python将单个元素列表视为 Python 中的标量
【发布时间】:2018-11-14 10:54:14
【问题描述】:

¿是否可以定义一个 python 列表的子类,允许使用单元素列表变量,就好像它们是标量一样?

例如我希望能够做到:

class CustomList(list):
    ...
    ...

list1 = CustomList([2])
list2 = CustomList([3])
list3 = CustomList([4,5,6])
list4 = CustomList([{'foo':'bar'}])
list1 #should return list1[0]
list4['foo'] #should return list4[0]['foo'] = 'bar'
list1 + list2 #should return list1[0] + list2[0] = 5

但保持正常使用列表的能力:

for i in list3:
    print list[i]

【问题讨论】:

  • 你希望加法有什么作用?像列表一样串联?
  • 定义一个class CustomList(list)正是需要的,你遇到了什么问题?
  • @MisterMiyagi "list1 + list2" 应该返回 list1[0] 和 list2[0] 的值之和。查看我的最后一次编辑。
  • 我知道你想要什么,但不是你的问题是什么。你不知道如何重载运算符吗?如何根据列表的长度进行切换?如何将基类行为用于非标量列表?
  • @MisterMiyagi 我没有定义类的经验,但我可以将 Green Cloak Guy 示例用于其他二元运算符。但是我不知道要使用什么方法来重新定义(或重载什么运算符),例如“print(list)”而不是“print(list[0])”。

标签: python list subclass


【解决方案1】:

是的,但您实际上需要覆盖您希望它使用的任何方法。

当您在列表等对象上调用某些运算符时,您最终会在这些对象上调用隐藏方法。在您给出的示例result = list1 + list2 中,实际调用的函数是list1.__add__(list2)。如果需要,您可以继承 list 并覆盖这些方法。例如:

class CustomList(list):
    def __add__(self, value):
        if len(self) == 1 and len(value) == 1:
            return self[0] + value[0]
        else:
            return CustomList(list.__add__(self, value))

如果list1list2 的长度都为1,则将它们视为标量,否则将参考正常的list 功能。 This stackoverflow answer on subclassing list 可能对你有帮助。


要解决您的编辑问题,更通用的解决方案将相当简单 - 尝试覆盖 __getitem__(),而不是覆盖 __add__() 函数,每当您使用方括号运算符时都会调用该函数:

class CustomList(list):
    def __getitem__(self, y):
        if len(self) == 1:
            return self[0][y]
        else:
            return self[y]

但是,这可能会在尝试连接数组时引起问题; list3 + list1 会导致错误,因为 list1 不是可迭代的,当然如果列表长度超过一个元素,您可以覆盖 __add__ 以简单地将第二个值添加为列表元素。


使用上述声明的控制台输出:

>>> list1 = CustomList([2])
>>> list2 = CustomList([3])
>>> list3 = CustomList([4,5,6])
>>> print(list1 + list2)
5
>>> print(list2 + list3)
[3, 4, 5, 6]

【讨论】:

  • 添加可能会返回另一个CustomList,而不是普通的list
  • 谢谢,这正是我想用算术运算符做的,但我仍然不知道如何处理类似:list4 = "CustomList[{'foo':'bar '}]”,然后执行“print(list4['foo'])”而不是“print(list4[0]['foo'])”。查看我的编辑。
  • 如果你想让它像字典一样工作,那么你也可以覆盖__getitem__() 方法,只要你使用方括号运算符就会激活它。我在我的帖子中编辑了一个简单的例子,当然你应该做任何你需要做的事情来使它适合你的实现
  • @GreenCloakGuy 太棒了!我想我可以使用你的最后一个例子。列表连接不是问题,因为我不会使用子类来替代标准列表类。
【解决方案2】:

假设通过添加两个类意味着连接两个列表,您可以执行以下操作(注意 __add__ 方法以了解添加的工作原理):

from collections import MutableSequence

class CustomList(MutableSequence):
    def __init__(self, data=[]):
        self._list = data 

    def __add__(self, newlist):
        return self._list + newlist._list

    def __len__(self):
        return len(self._list)

    def __getitem__(self, i):
        return self._list[i]

    def __delitem__(self, i):
        del self._list[i]

    def __setitem__(self, i, val):
        self._list[i] = val

    def __str__(self):
        return str(self._list)

    def insert(self, i, val):
        self._list.insert(i, val)

【讨论】:

  • list 可以直接子类化,不需要写那么多样板。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2019-02-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多