【问题标题】:In Python, how to avoid calling __init__ twice in a class derived from a class with super() in its __new__:在 Python 中,如何避免在从 __new__ 中带有 super() 的类派生的类中调用 __init__ 两次:
【发布时间】:2016-09-21 01:32:39
【问题描述】:

我是 python 新手。不知何故

__init__

为从另一个类派生的类调用两次

super()

我的问题是如何避免这种情况,因为那里的计算非常昂贵。

class A(object):
  def __new__(cls, *args, **kwargs):
    print("Class A: __new__")
    obj = super(A, cls).__new__(cls) # super is used here
    obj.__init__(*args, **kwargs)
    return obj
  def __init__(self, x):
    self.attrib = x+1

class B(A):
  def __init__(self, x):
    print("Class B: __init__")
    self.prop = 2*x # some expensive computation

a = A(10) # a test call

b = B(20) # Q: here, how to avoid calling __init__ twice in class B?

编辑: 谢谢两位的回答。我的真实代码是使用 scipy 库中内置的 arpack 对大型稀疏矩阵进行对角化。我正在调用在 arpack.py 中定义的类 SpLuInv(LinearOperator),其中在 interface.py 中定义了类 LinearOperator,两个文件均已附加:arpack.pyinterface.py。当我调用 SpLuInv() 时,它的 init 会被调用两次。根据您的回答,我认为我需要删除 LinearOperator() 的 new 中的 obj.init

感谢 Brendan Abel 的回答以及 Akshat Mahajan 和 Mike Graham 的 cmets。删除

obj.__init__

来自

__new__

LinearOperator()

解决了这个问题。 :)

【问题讨论】:

  • 你真的需要从A继承吗?为什么不在B 中定义你想要的具体方法呢?
  • 定义__new__ 实际上总是一种次优方法。考虑分享你真实的代码。

标签: python super derived-class


【解决方案1】:

您不应该在__new__ 中手动调用__init__。从__new__ 返回的对象将自动调用__init__

应该在你的所有类中调用超类__init__,即使它们只继承自object

唯一出现问题的情况是像 singleton 对象这样的对象,这些对象通常会从 __new__ 返回一个已经 __init__'d 的对象。在这种情况下,您只需将类的实例存储为类属性,如果设置了属性,则直接从__init__ 返回。

class A(object):
    def __new__(cls, *args, **kwargs):
        print("Class A: __new__")
        obj = super(A, cls).__new__(cls) # super is used here
        return obj

    def __init__(self, x):
        super(A, self).__init__()
        self.attrib = x+1

class B(A):
    def __init__(self, x):
        print("Class B: __init__")
        super(B, self).__init__(x)
        self.prop = 2*x # some expensive computation

【讨论】:

  • Nit: metaclass.__call__ 只会在 __new__ 返回该类型的实例(包括子类)时调用 __init__。如果您重写 __new__ 以返回缓存对象(然后 __init__ 将被多次调用)或不同类的对象(然后 __init__ 将根本不会为您调用),这很重要。
猜你喜欢
  • 1970-01-01
  • 2019-10-31
  • 2013-12-19
  • 2017-06-30
  • 1970-01-01
  • 2019-09-01
  • 1970-01-01
  • 2023-03-22
  • 2017-08-26
相关资源
最近更新 更多