簡體   English   中英

python:在__init__方法中過早地調用super().__ init__?

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM