簡體   English   中英

如何從基礎 class 中的派生 class 調用方法?

[英]How to call method from a derived class in the base class?

我正在嘗試編寫一個干凈的代碼,並通過這樣做學習一兩件事。

class Building:
    def __init__(self, db):
        self.__db = db
    def decode(self, value):
        field = dict()
        for key in self.__db:
            field[key] = int(value)
        return field

class Apartment(Building):
    def __init__(self, db):
        super().__init__(db)

    def decode(self, str_value):
        field = super().decode(str_value)
        field = self.scaling(field)     
        return field         

    def scaling(self, field):
        field['size'] /= 1000
        return field

class Home(Building):
    def __init__(self, db):
        super().__init__(db)

    def decode(self, str_value):
        field = super().decode(str_value)
        field = self.scaling(field)
        return field

    def scaling(self, field):
        field['garden'] /= 25
        return field

def main():
    apartment_db = { 'size' : None}
    home_db = { 'garden' : None}
    app = Apartment(apartment_db)
    home = Home(home_db)
    print(app.decode('5'))
    print(home.decode('100'))

if __name__ == "__main__":
    main()

Output:

 {'size': 0.005} {'garden': 4.0}

可以看出,每個派生的 class 都有自己的數據庫和自己的縮放比例(我認為沒有縮放比例也是縮放比例)。

我的思考問題是基礎 class 不知道縮放實現,它在派生的 class 中定義。

如果我可以將派生 class 的縮放實現傳遞給基礎 class,那么我在派生 class 中的解碼方法將非常簡單:

class Apartment(Building):
    def decode(self,str_value):
        return super().decode(str_value)

有沒有辦法在 python3.7 中做到這一點?

對的,這是可能的。

如果您對向Building class 添加新方法感到滿意,那么一種簡單的方法就是向其添加scaling方法。 現在派生類沒有自己的scaling定義,將只使用Building的簡單實現:

class Building:
    def __init__(self, db):
        self.__db = db

    def decode(self, value):
        field = dict()
        for key in self.__db:
            field[key] = int(value)
        return self.scaling(field)

    def scaling(self, value):
        return value

如果您不想向Building添加方法,您仍然有一些選擇。 在你跳躍之前的方法是檢查self是否具有屬性'scaling' ,然后將field傳遞self.scaling如果這是真的。 這是因為self始終是我們調用該方法的實例,因此它將具有為該對象的 class 定義的屬性。 這是一個快速的實現:

class Building:
    def __init__(self, db):
        self.__db = db

    def decode(self, value):
        field = dict()
        for key in self.__db:
            field[key] = int(value)

        if hasattr(self, 'scaling'):
            field = self.scaling(field)

        return field

或者,比許可更容易請求寬恕的方式是使用try-except ,並在方法不存在時捕獲AttributeError並且不進行縮放:

class Building:
    def __init__(self, db):
        self.__db = db

    def decode(self, value):
        field = dict()
        for key in self.__db:
            field[key] = int(value)

        try:
            field = self.scaling(field)
        except AttributeError:
            pass

        return field

這也可以在不添加任何方法甚至不使用if -statement 或try-except的情況下完成,帶有一種有趣的 hack。 這將傳遞一個 lambda,它只返回其參數(=identity 函數),作為gettattr function 的第三個參數。 第 3 個參數是gettattr在找不到給定屬性時返回的默認值。 然后我們簡單地以field作為參數調用gettattr的返回值並返回結果:

class Building:
    def __init__(self, db):
        self.__db = db

    def decode(self, value):
        field = dict()
        for key in self.__db:
            field[key] = int(value)
        return getattr(self, 'scaling', lambda x: x)(field)

以上所有方法都可以讓您從派生類中刪除__init__decode方法,並讓它們在必要時實現scaling 像這里這樣使用時,它們也會給出相同的結果:

class Building:
    # Any of the above implementations,
    # will give the exact same results.

class Apartment(Building):
    def scaling(self, field):
        field['size'] /= 1000
        return field

class Home(Building):
    def scaling(self, field):
        field['garden'] /= 25
        return field

def main():
    apartment_db = { 'size' : None}
    home_db = { 'garden' : None}
    app = Apartment(apartment_db)
    home = Home(home_db)
    print(app.decode('5'))
    print(home.decode('100'))

if __name__ == "__main__":
    main()

Output:

 {'size': 0.005} {'garden': 4.0}

Inheritance 從 Base class 工作到 Derived class,所以簡而言之,我不相信你可以從 Base-class 調用 Derived-class 方法。 如果我們在談論實例,那么也許有一些技巧。

將 Derived class 視為 Base class 的專業化也是一種很好的做法,因此常見行為仍保留在 Base class 中,您只需調整(也稱為覆蓋)一些特定目的和方法的參數和方法。 這使得整個代碼更具可讀性和可維護性。

對於您的特定情況,我可以想到一個不同的解決方案,您可以將縮放直接嵌入到 Base class 中,並僅在派生類中更改縮放因子,例如:

class Base(object):
    def __init__(self):
        self.scaling = 1

    def decode(self, value):
        field = { 'distance' : int(value)/self.scaling }
        return field


class Derived(Base):
    def __init__(self):
        self.scaling = 1000

base = Base()
print(base.decode(5))

derived = Derived()
print(derived.decode(5))

在這種情況下,您需要更改的只是從Base派生的任何 class 中的self.scaling值。 您的現實世界場景可能更復雜,但我相信這種范式會更好地為您服務。

您可以采取兩種方法。 首先,將scaler設為 function 參數以進行decode 它不需要是一個方法,因為你沒有使用它的self參數。 (Although for each derived class implementation, I'll define each class's scaler as a private static method. Note, though, that you don't need a derived class simply to define a scaler; you can instantiate Building directly and pass an appropriate function直接到Building.decode )

class Building:
    def __init__(self, db):
        self.__db = db

    def decode(self, value, scaler=lambda x: x):
        field = dict()
        for key in self.__db:
            field[key] = int(value)
        return scaler(field)


class Apartment(Building):
    @staticmethod
    def _scale_by_1000(d):
        d['size'] /= 1000
        return d

    def decode(self, str_value):
        return super().decode(str_value, self._scale_by_1000)


class Home(Building): 
    @staticmethod
    def _scale_by_25(d):
        d['garden'] /= 25
        return d

    def decode(self, str_value):
        return super().decode(str_value, self._scale_by_25)

或者,在Building中定義一個無操作scaling方法,並根據需要讓派生的 class 覆蓋它。

class Building:
    def __init__(self, db):
        self.__db = db

    def decode(self, value):
        field = dict()
        for key in self.__db:
            field[key] = int(value)
        return self.scaling(field)

    def scaling(self, d):
        return d


class Apartment(Building):
    def scaling(self, field):
        field['size'] /= 1000
        return field


class Home(Building):
    def scaling(self, field):
        field['garden'] /= 25
        return field

請注意,在這兩種情況下,我都放棄了像__init__這樣的重寫方法,其中派生的 class 什么都不做,只是使用super調用具有相同 arguments 的父方法。 Inheritance 確保在未定義覆蓋時調用父級。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

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