【问题标题】:Python 3 super and metaprogrammingPython 3 超级和元编程
【发布时间】:2017-04-10 16:21:02
【问题描述】:

我正在尝试复制然后以编程方式修改一个类,但我遇到了 python 3 的魔法超级问题,例如以下

class Base():
    def __init__(self):
        print("Base init")

class Orginal(Base):
    def __init__(self):
        super().__init__()
        print("Orginal init")

Modified = type(Orginal.__name__, Orginal.__bases__, dict(Orginal.__dict__))
Modified.f = lambda self: print("f")

m = Modified()

提高

TypeError: super(type, obj): obj 必须是类型的实例或子类型

所以我想知道,有什么方法可以帮助 super() 在通过 type() 创建的类中找到正确的 __class__ 单元格?

【问题讨论】:

  • 我认为你的课程应该命名为“Original”。

标签: python inheritance metaprogramming typeerror super


【解决方案1】:

注意我在这个答案中更正了Original 的拼写


问题似乎在于,当您的Modified 对象被实例化并调用super 时,它的调用方式如下:super(Original, self),因为这些是super 的默认参数。由于Original 不是Modified 的超类(检查isinstance(m, Original)),python 不允许您以这种方式调用super

以下代码与您的代码类似,但更能说明问题。

class Base():
    def __init__(self):
        print("Base init")

class Original(Base):
    def __init__(self):
        super().__init__()
        print("Orginal init")

class Modified(Base):
    def __init__(self):
        super(Original, self).__init__()  # illegal 

Modified.__name__ == Original.__name__

m = Modified()  # raises same Exception that your your code does

Original 添加到Modifiedbases 将使其工作:

Modified = type(Original.__name__, (Original,) + Original.__bases__, dict(Original.__dict__))

编辑

根据 cmets,上述建议可以简化,因为 Original 中包含的所有方法都将包含在 Modified 中,而无需在 type 调用中传递 dict

Modified = type(Original.__name__, (Original,), {})

更进一步,如果您不希望Modified 成为Original 的子类,您可以简单地将Modified 复制为Original,然后添加与你在你的例子中做了:

from copy import deepcopy
Modified = deepcopy(Original)
Modified.f = lambda self: print("f")

m = Modified()

查看this answer,您似乎不能使用deepcopy 来复制类,并且鉴于您在Original.__init__ 方法中有super() 调用,ModifiedOriginal 的子类(除非您在“复制”后还修改了 Modified 类中的 __init__ 方法。

【讨论】:

  • 仅供参考,如果Original 在基础中,则无需添加Original.__bases__dict(Original.__dict__)Modified = type(Original.__name__, (Original,), {}) 就足够了。
  • 使用 deepcopy 是个好主意,这正是我所需要的——但它似乎并没有真正起作用。如果我覆盖任何 Original 的属性,Modified 的也会改变!
【解决方案2】:

根据the documentation

还要注意,除了零参数形式之外,super() 不限于使用内部方法。两个参数形式精确地指定参数并进行适当的引用。 零参数形式仅适用于类定义,因为编译器会填写必要的详细信息以正确检索正在定义的类,以及访问普通方法的当前实例。

所以,代码中的super()等价于super(Orginal, self).__init__(),是在编译时确定的。

【讨论】:

  • 它实际上添加了一个包含该类的__class__ 单元格,您可以在该函数中进行操作。但丹尼尔邦廷已经知道这一点,从他问题的最后一部分来看。他在问如何设置单元格的值。
猜你喜欢
  • 2016-08-11
  • 1970-01-01
  • 2013-12-02
  • 2019-11-07
  • 1970-01-01
  • 1970-01-01
  • 2021-01-06
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多