在Python中替换列表对象的__str__方法

15 投票
8 回答
12094 浏览
提问于 2025-04-15 11:56

这看起来应该很简单:

我想要一个 list,和其他的 list 一样,只是它的 .__str__ 方法不一样。

  1. 尝试用 object.__str__ = foo 来设置时,结果出现了只读错误。
  2. 如果想要继承 list,那就需要有办法把一个现有的 list 转换成这个子类的实例。这就需要手动复制所有属性(这太麻烦了),或者以某种方式自动复制所有属性,但我不知道怎么做。
  3. 如果想要在 list 对象周围写一个包装器,那我就得想办法把所有消息都发送给被包装的对象,除了 .__str__,这个我用自己的方法来处理。我不知道怎么做到这一点。

任何替代方案,或者解决方案 #2 或 #3 都非常感谢。谢谢!

8 个回答

5

你可以扩展列表类,并重写它:

class myList(list):
  def __str__(self):
    # do something
    return "something"

补充说明:删除了答案中一个不正确的部分,之前提到可以动态替换列表对象的 __str__,但在Python列表的实现中这是不允许的。

7

如果你想要为其他容器(比如说 tuple)重写 __str__ 方法,你可以利用多重继承的特性:

class PrettyStr(object):
    def __str__(self):
        ret = ''

        if isinstance(self, (list, tuple)):
            ret = ''.join(str(elem) for elem in self)
        else:
            pass  # handle other types here

        return ret


class MyList(PrettyStr, list):
    pass


class MyTuple(PrettyStr, tuple):
    pass


if __name__ == "__main__":
    print MyList([1, 2, 3, 4])
    print MyTuple((1, 2, 3, 4))
13

这个解决方案不需要额外的包装就能正常工作。而且如果你用加法把两个列表合并在一起,它也能正常运作。任何会修改列表本身的操作都会按预期工作。只有那些返回列表副本的函数,比如:sorted(排序)和reversed(反转),会返回原生的Python列表,这样也是可以的。另一方面,sort(排序)和reverse(反转)是直接在列表上操作的,它们会保持列表的类型。

class myList(list):
    def __new__(cls, data=None):
        obj = super(myList, cls).__new__(cls, data)
        return obj

    def __str__(self):
        return 'myList(%s)' % list(self)

    def __add__(self, other):
        return myList(list(self) + list(other))

>>> l = myList(range(5))
>>> print l
myList([0, 1, 2, 3, 4])
>>> print l + [1, 2]
myList([0, 1, 2, 3, 4, 1, 2])
>>> l.sort()
>>> print l
myList([0, 1, 2, 3, 4])

撰写回答