Python 3:如何为派生类编写__iter__方法,以便它扩展到基类'__iter__方法

时间:2018-01-22 07:35:51

标签: python inheritance override iterable

说我有一个基类:

class Base:
    A = False
    B = ''
    C = ''

    def __iter__(self):
        yield 'a', self.A
        yield 'b', self.B
        yield 'c', self.C

然后是一个派生自这个基础的类:

class Data(Base):
    D = ''

    def __iter__(self):
        yield 'd', self.D

如果数据类的实例转换为{ 'd': <value> }类型,则此事件仅在dict( Data() )上创建包含dict的字典;因为据我所知,派生类__iter__方法有效地覆盖了基类__iter__方法。

然后我尝试从派生类覆盖方法调用基类方法,就像在__init__()函数中一样:

def __iter__(self):
    super().__iter__()
    yield 'd', self.D

但是IDE将其标记为错误。为什么这不起作用? 以及如何定义派生的iter方法以扩展已经存在的基类iter方法,这样我只需要为派生类中添加的变量添加yield?是否在派生类iter方法中再次手动写出所有的产量,这是我实现它的那一刻,唯一的解决方案?为什么呢?

class Data(Base):
    D = ''

    def __iter__(self):
        yield 'a', self.A
        yield 'b', self.B
        yield 'c', self.C
        yield 'd', self.D

2 个答案:

答案 0 :(得分:2)

这不会起作用,因为super().__iter__()是一个生成器并且在这种情况下调用生成器是没有意义的。您要做的是迭代该生成器返回的内容,并从__iter__中的Data中生成它们:

Python 2:

def __iter__(self):
    for i in super().__iter__():
        yield i
    yield 'd', self.D

但是在Python 3中,这可以更简洁地写成:

def __iter__(self):
    yield from super().__iter__()
    yield 'd', self.D

答案 1 :(得分:1)

您必须委托给基类:

In [1]: class Base:
   ...:     A = False
   ...:     B = ''
   ...:     C = ''
   ...:
   ...:     def __iter__(self):
   ...:         yield 'a', self.A
   ...:         yield 'b', self.B
   ...:         yield 'c', self.C
   ...:

In [2]: class Data(Base):
   ...:     D = ''
   ...:
   ...:     def __iter__(self):
   ...:         yield from super().__iter__()
   ...:         yield 'd', self.D
   ...:

In [3]: print(list(Data()))
[('a', False), ('b', ''), ('c', ''), ('d', '')]

In [4]: print(dict(Data()))
{'c': '', 'b': '', 'd': '', 'a': False}

Python 3允许使用yield from语法,在Python 2中使用:

class Base(object): # make sure to inherit from object for super to work
    A = False
    B = ''
    C = ''

    def __iter__(self):
        yield 'a', self.A
        yield 'b', self.B
        yield 'c', self.C

class Data(Base):
    D = ''

    def __iter__(self):
        for x in super(Data, self).__iter__():
            yield x
        yield 'd', self.D