代码之家  ›  专栏  ›  技术社区  ›  Chris Morgan

如何重写Python列表(迭代器)行为?

  •  6
  • Chris Morgan  · 技术社区  · 14 年前

    运行此:

    class DontList(object):
        def __getitem__(self, key):
            print 'Getting item %s' % key
            if key == 10: raise KeyError("You get the idea.")
            return None
    
        def __getattr__(self, name):
            print 'Getting attr %s' % name
            return None
    
    list(DontList())
    

    产生这个:

    Getting attr __length_hint__
    Getting item 0
    Getting item 1
    Getting item 2
    Getting item 3
    Getting item 4
    Getting item 5
    Getting item 6
    Getting item 7
    Getting item 8
    Getting item 9
    Getting item 10
    Traceback (most recent call last):
      File "list.py", line 11, in <module>
        list(DontList())
      File "list.py", line 4, in __getitem__
        if key == 10: raise KeyError("You get the idea.")
    KeyError: 'You get the idea.'
    

    我怎样才能改变它 [] ,同时仍允许访问这些密钥 [1] 等。?

    (我试过把 def __length_hint__(self): return 0 ,但没有帮助。)

    我的真实用例: (如果有用的话,请仔细阅读;请忽略这一点)

    申请后 a certain patch 我发现我的贴片有一个讨厌的副作用。有 __getattr__ 以我的 Undefined 类,它返回一个新的 未定义 反对。不幸的是,这意味着 list(iniconfig.invalid_section) (其中 isinstance(iniconfig, iniparse.INIConfig) )做这个(简单地说 print s在 __格塔特__ __getitem__ ):

    Getting attr __length_hint__
    Getting item 0
    Getting item 1
    Getting item 2
    Getting item 3
    Getting item 4
    

    等等。

    5 回复  |  直到 14 年前
        1
  •  7
  •   Katriel    14 年前

    如果要重写迭代,那么只需定义 __iter__ 你班的方法

        2
  •  3
  •   Community CDub    7 年前

    作为 @Sven 说,这是错误的错误提出。但这不是重点,关键是这是因为 不是你该做的事 :防止 __getattr__ 从抚养 AttributeError 意味着您已经重写了Python用于测试对象是否具有属性的默认方法,并将其替换为新的( ini_defined(foo.bar) ).

    但Python已经 hasattr ! 为什么不用那个?

    >>> class Foo:
    ...     bar = None
    ...
    >>> hasattr(Foo, "bar")
    True
    >>> hasattr(Foo, "baz")
    False
    
        3
  •  3
  •   Sven Marnach    14 年前

    只是提高 IndexError 而不是 KeyError . 键错误 用于类的映射(例如。 dict ),而 索引器 用于序列。

    如果你定义了 __getitem__() 方法,Python将从中自动生成迭代器。迭代器终止于 索引器 --见 PEP234 .

        4
  •  1
  •   martineau    14 年前

    通过实现 __iter__() 方法。迭代器信号,当它们通过提升 StopIteration 异常,它是常规迭代器协议的一部分,不会进一步传播。下面是将其应用于示例类的一种方法:

    class DontList(object):
        def __getitem__(self, key):
            print 'Getting item %s' % key
            if key == 10: raise KeyError("You get the idea.")
            return None
    
        def __iter__(self):
            class iterator(object):
                def __init__(self, obj):
                    self.obj = obj
                    self.index = -1
                def __iter__(self):
                    return self
                def next(self):
                    if self.index < 9:
                        self.index += 1
                        return self.obj[self.index]
                    else:
                        raise StopIteration
    
            return iterator(self)
    
    list(DontList())
    print 'done'
    # Getting item 0
    # Getting item 1
    # ...
    # Getting item 8
    # Getting item 9
    # done
    
        5
  •  0
  •   Mutantoe Andrew Lygin    9 年前

    我认为使用 return iter([]) 是正确的方法,但是让我们开始思考 list() 作品:

    从中获取元素 __iter__ ;如果收到 StopIrteration 错误停止..然后获取该元素。。

    所以你必须 yield 空发电机 __iter__ ,例如 (x for x in xrange(0, 0)) ,或者只是 iter([]))