根据文档,由于以下原因,此方法不起作用:
对于自定义类,只有在对对象的类型(而不是在对象的实例字典中)进行定义的情况下,才能保证对特殊方法的隐式调用可以正常工作。该行为是以下代码引发异常的原因:
>>> class C: ... pass ... >>> c = C() >>> c.__len__ = lambda: 5 >>> len(c) Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: object of type 'C' has no len()
https://docs.python.org/3/reference/datamodel.html#special-method-lookup
我曾在没有__len__
的函数生成器上尝试过此操作,但我事先知道了它的长度,然后,我尝试用c.__len__ = lambda: 5
之类的东西对猴子进行补丁,但它一直说生成器对象没有长度。
这是生成器:
def get_sections(loaded_config_file):
for module_file, config_parser in loaded_config_file.items():
for section in config_parser.sections():
yield section, module_file, config_parser
我正在将生成器(没有长度)传递给另一个函数(但另一个生成器),该函数需要通过调用len()
来迭代长度:
def sequence_timer(sequence, info_frequency=0): i = 0 start = time.time() if_counter = start length = len(sequence) for elem in sequence: now = time.time() if now - if_counter < info_frequency: yield elem, None else: pi = ProgressInfo(now - start, float(i)/length) if_counter += info_frequency yield elem, pi i += 1
https://github.com/arp2600/Etc/blob/60c5af803faecb2d14b5dd3041254ef00a5a79a9/etc.py
然后,在尝试将__len__
属性添加到get_sections
时出现错误:
get_sections.__len__ = lambda: calculated_length
for stuff, progress in sequence_timer( get_sections ):
section, module_file, config_parser = stuff
TypeError: object of type 'function' has no len()
答案 0 :(得分:4)
您不能将其添加到现有对象中,因此请创建自己的包装类,该包装类具有您控制的类级别的定义:
class KnownLengthIterator:
def __init__(self, it, length):
self.it = it
self.length = int(length)
def __len__(self):
return self.length
def __iter__(self):
yield from self.it
现在,您只需更改无效的尝试即可将长度设置为:
get_sections.__len__ = lambda: calculated_length
有效地重新包装,使get_sections
继续是有效的生成器(yield from
将所有迭代行为委派给包装的生成器),同时也公开了长度:
get_sections = KnownLengthIterator(get_sections, calculated_length)
无需更改其他代码。