假设我正在构建一个
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__
方法中中继以能够显示进度条
您可以使用
__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
,但不要直接对其进行子类化。
创建一个新类,为新类定义函数并使用它代替原来的类。