【问题标题】:Python 3: How to write a __iter__ method for derived class so that it extends on the behaviour of the base class' __iter__ methodPython 3:如何为派生类编写 __iter__ 方法,以便它扩展基类的 __iter__ 方法的行为
【发布时间】:2018-06-30 18:58:24
【问题描述】:

假设我有一个基类:

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

这当然只会在dict( Data() )上创建一个包含{ 'd': <value> }的字典,当数据类的实例转换为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

【问题讨论】:

  • 请注意:这里没有创建字典。您的迭代器产生的元组可以传递给 dict(例如 dict(Base())dict(Data())),但这不是一回事。
  • @BaileyParker 是的,这就是我的意思。我将实例传递给 dict() 以便我可以创建数据的 json

标签: python inheritance overriding iterable


【解决方案1】:

这不起作用,因为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

【讨论】:

    【解决方案2】:

    您必须委托给基类:

    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
    

    【讨论】:

    • 感谢您提供如此详细的代码并得到您的回答。由于贝利帕克的答案也包含我正在寻找的推理,我将接受这个答案。希望你不要介意。
    猜你喜欢
    • 2010-11-16
    • 1970-01-01
    • 2019-12-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-09-09
    • 2013-04-27
    • 2019-05-16
    相关资源
    最近更新 更多