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

cig3rfwq  于 2023-04-19  发布在  Python
关注(0)|答案(2)|浏览(168)

假设我正在构建一个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__方法能够显示进度条

ufj5ltwl

ufj5ltwl1#

你可以使用__new__.See here for why.来扩展这个类。以你的例子为例,我们可以这样写:

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

虽然返回这个生成器的长度有点尴尬,因为内容在第一次迭代后就耗尽了(你只能在生成器上循环一次,它不会存储)。
你可能需要的是一个简单的helper,它允许简单的链接,但返回一个支持多次迭代和len的列表实现。

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

这可能会变得非常昂贵,这取决于提供的可迭代对象(比如range(1, 1000000000))。在这种情况下,您可能应该定义自己的接口来实现__iter__等方法,可能会在后台使用itertools.chain,但不要直接子类化它。

4xrmg8kj

4xrmg8kj2#

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

相关问题