我有一个类层次结构,其中__init__
class Base
执行一些预初始化,然后调用方法calculate
。 calculate
方法在class Base
中定义,但预计会在派生类中重新定义。重新定义的calculate
将使用class Derived
中仅提供的一些属性:
class Base:
def __init__(self, args):
# perform some pre-initialization
...
# now call method "calculate"
self.calculate()
class Derived(Base):
def __init__(self, args, additional_attr):
super().__init__(args)
# do some work and create new instance attributes
...
self.additional_attr = additional_attr
这不起作用,因为calculate
中的class Derived
方法将在分配self.additional_attr之前调用。
我无法将super().__init__(args)
调用移至__init__
方法的末尾,因为它必须在处理additional_attr
之前完成一些工作。
怎么办?
答案 0 :(得分:7)
也许你不应该在你的构造函数中调用calculate()
。如果你不能通过允许基础构造函数首先完成来构造派生对象,那么你必须做错了恕我直言。一种明智的方法是将该调用移出构造函数,并可能创建一个工厂方法来自动进行调用。如果需要预先计算的实例,请使用该方法。
class Base(object):
def __init__(self, args):
# perform some initialization
pass
def calculate(self):
# do stuff
pass
@classmethod
def precalculated(cls, args):
# construct first
newBase = cls(args)
# now call method "calculate"
newBase.calculate()
return newBase
class Derived(Base):
def __init__(self, args, additional_attr):
super(Derived, self).__init__(args)
# do some work and create new instance attributes
self.additional_attr = additional_attr
@classmethod
def precalculated(cls, args, additional_attr): # also if you want
newDerived = cls(args, additional_attr)
newDerived.calculate()
return newDerived
newBase = Base('foo')
precalculatedBase = Base.precalculated('foo')
newDerived = Derived('foo', 'bar')
precalculatedDerived = Derived.precalculated('foo', 'bar')
答案 1 :(得分:4)
这是糟糕的设计,恕我直言,你正在使用Python的对象系统。考虑到在其他OO语言(如C ++)中,您甚至无法控制基类的创建。派生类的构造函数在代码运行之前调用基础构造函数。这种行为几乎总是需要表现良好的类层次结构,而改变它只会导致问题。
当然,您可以进行一些修补(例如在调用self.additional_attr
的构造函数或其他技巧之前分配super
),但更好的方法是更改您的设计以便它不会要求这样的黑客攻击。既然你已经在这里提出了一个抽象的例子,那么很难给出更全面的设计建议。
答案 2 :(得分:2)
为了使这样的东西能够工作,你需要设计一个协议,允许基类和派生类相互合作以完成对象初始化任务:
class Base:
def __init__(self, args, *additional_args):
# perform some pre-initialization
# ...
# perform any futher initialization needed by derived classes
self.subclass_setup(*additional_args)
# now call method "calculate"
self.calculate()
def subclass_setup(self, *args):
pass
class Derived(Base):
def __init__(self, args, additional_attr):
super().__init__(args, additional_attr)
def subclass_setup(self, additional_attr):
# do some work and create new instance attributes
# ...
self.additional_attr = additional_attr
答案 3 :(得分:1)
您可以将additional_attr
作为参数传递给基类的__init__
方法,并将其从那里传播到calculate
方法吗?
说出类似的话:
class Base(object):
def __init__(self, args,additional_attr):
print 'Args for base class:%s' %(args)
self.calculate(additional_attr)
class Derived(Base):
def __init__(self, args, additional_attr):
super(Derived,self).__init__(args,additional_attr)
def calculate(self,val):
print 'Arg for calculate:%s' %(val)
self.additional_attr = val
>>> d = Derived(['test','name'],100) Args for base class:['test', 'name'] Arg for calculate:100
这是迂回的方式,但由于没有关于预初始化步骤的信息,很难说上述方法是否会对您有所帮助。