代码之家  ›  专栏  ›  技术社区  ›  Evandro Coan

如何在数据类型定义中没有uuu len_uuuu的情况下将uuu len_uuu添加到对象中?

  •  4
  • Evandro Coan  · 技术社区  · 6 年前

    根据文件,这不起作用,因为:

    >>> 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

    然后,当尝试添加 __莱恩__ 把某事归因于某人 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()

    1 回复  |  直到 6 年前
        1
  •  4
  •   ShadowRanger    6 年前

    您无法将其添加到现有对象,因此请创建自己的包装类,该包装类具有您可以控制的类级别定义:

    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)
    

    没有其他代码需要更改。