繁体   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