如何为 itertools.chain 对象设置 __len__ 方法?

问题描述 投票:0回答:2

假设我正在构建一个

itertools.chain
实例如下:

from itertools import chain

list_1 = list(range(5, 15))
list_2 = list(range(20, 30))
chained = chain(list_1, list_2)

现在,因为我已经知道

chained
中包含的列表的长度,所以我可以很容易地得到
chained
的长度。我怎样才能将
__len__
添加到
chained

我试过这个:

full_len = len(list_1) + len(list_2)
setattr(chained, '__len__', lambda: full_len)

但它因错误而失败

AttributeError: 'itertools.chain' object has no attribute '__len__'

编辑: 我需要它能够用

tqdm
显示一个长过程的进度,它在
__len__
方法中中继以能够显示进度条

python attributeerror
2个回答
1
投票

您可以使用

__new__
扩展课程。 在这里查看原因。。以你的例子我们可以写:

class Chain(itertools.chain):
    def __new__(cls, *args):
        obj = super().__new__(cls, *args)
        obj.args = args
        return obj

    def __len__(self) -> int:
        return sum(map(len, self.args))
>>> chained = Chain([1], [2, 3])
>>> len(chained)
3

虽然返回这个生成器的长度有点尴尬,因为第一次迭代后内容就用完了(你只能循环一次生成器,它不存储)。

你可能想要的是一个简单的帮助器,它允许轻松链接,但返回一个支持多次迭代和 len 的列表实现。

def chain_list(*args):
    return list(itertools.chain(*args))

这可能会变得相当昂贵,具体取决于提供的迭代器(比如

range(1, 1000000000)
)。在这种情况下,您可能应该定义自己的接口来实现诸如
__iter__
之类的方法,可能会在幕后使用
itertools.chain
,但不要直接对其进行子类化。


0
投票

创建一个新类,为新类定义函数并使用它代替原来的类。

© www.soinside.com 2019 - 2024. All rights reserved.