[英]python: calling super().__init__ too early in the __init__ method?
我有一個類層次結構,其中class Base
中的__init__
執行一些預初始化,然后調用方法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
這不起作用,因為在分配self.additional_attr之前將調用class Derived
calculate
方法。
我無法移動super().__init__(args)
調用__init__
方法的結尾,因為它的一些工作必須在處理additional_attr
之前發生。
該怎么辦?
也許你不應該在你的構造函數中調用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')
這是糟糕的設計,恕我直言,而你正在使用Python的對象系統。 考慮到在其他OO語言(如C ++)中,您甚至無法控制基類的創建。 派生類的構造函數在代碼運行之前調用基礎構造函數。 幾乎總是期望這種行為表現良好的類層次結構,而改變它只會導致問題。
當然,您可以進行一些修補(例如在調用super
的構造函數或其他技巧之前分配self.additional_attr
),但更好的方法是更改您的設計,以便它不需要這樣的黑客攻擊。 由於您在此處提供了一個抽象示例,因此很難提供更全面的設計建議。
為了使這樣的東西能夠工作,你需要設計一個協議,允許基類和派生類相互合作來完成對象初始化任務:
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
你可以將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
這是迂回的方式,但由於沒有關於預初始化步驟的信息,很難說上述方法是否會對您有所幫助。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.