简体   繁体   English

如何从基础 class 中的派生 class 调用方法?

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

I am trying to write a clean code and by doing this learning one or two things.我正在尝试编写一个干净的代码,并通过这样做学习一两件事。

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: Output:

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

As it can be seen, each derived class have its own databank and its own scaling (no scaling is in my opinion is scaling as well).可以看出,每个派生的 class 都有自己的数据库和自己的缩放比例(我认为没有缩放比例也是缩放比例)。

My thinking problem is that the base class do not know the scaling implementation, which is defined in the derived class.我的思考问题是基础 class 不知道缩放实现,它在派生的 class 中定义。

If i could pass the scaling implementation of the derived class to the base class, then my decode method in the derived class will be very simply:如果我可以将派生 class 的缩放实现传递给基础 class,那么我在派生 class 中的解码方法将非常简单:

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

Is there a way to do it in python3.7?有没有办法在 python3.7 中做到这一点?

Yes it is possible.对的,这是可能的。

If you are fine with adding a new method to the Building class, a simple way would be add the scaling method to it as well.如果您对向Building class 添加新方法感到满意,那么一种简单的方法就是向其添加scaling方法。 Now the derived classes, which don't have their own definition for scaling , will just use the Building 's trivial implementation:现在派生类没有自己的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

If you don't want to add a method to Building , you still have some options.如果您不想向Building添加方法,您仍然有一些选择。 The look before you leap way to do this, would be to check if self has the attribute 'scaling' , and then pass field through self.scaling if that is true.在你跳跃之前的方法是检查self是否具有属性'scaling' ,然后将field传递self.scaling如果这是真的。 This works becuse self is always the instance which we are calling the method on, so it will have the attributes that are defined for that object's class.这是因为self始终是我们调用该方法的实例,因此它将具有为该对象的 class 定义的属性。 Here's a quick implementation of that:这是一个快速的实现:

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

Alternatively, the easier to ask forgiveness than permission way, would be to use try-except , and catch the AttributeError and do no scaling when the method doesn't exist:或者,比许可更容易请求宽恕的方式是使用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

This can be also done without adding any methods and even without using an if -statement or try-except , with a kinda funny hack.这也可以在不添加任何方法甚至不使用if -statement 或try-except的情况下完成,带有一种有趣的 hack。 This passes a lambda, which just returns its argument (=identity function), as the 3rd argument for the gettattr function.这将传递一个 lambda,它只返回其参数(=identity 函数),作为gettattr function 的第三个参数。 This 3rd argument is the default value that gettattr returns when it cannot find the given attribute.第 3 个参数是gettattr在找不到给定属性时返回的默认值。 Then we simply call the return value of the gettattr with the field as an argument and return the result of that:然后我们简单地以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)

All of the above ways will let you remove the __init__ and decode methods from the derived classes and have them just implement scaling if necessary.以上所有方法都可以让您从派生类中删除__init__decode方法,并让它们在必要时实现scaling They will also all give the same results when used like here:像这里这样使用时,它们也会给出相同的结果:

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: Output:

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

Inheritance works from Base class to Derived class, so in short, I don't believe you can call a Derived-class method from the Base-class. Inheritance 从 Base class 工作到 Derived class,所以简而言之,我不相信你可以从 Base-class 调用 Derived-class 方法。 If we are talking about instances then maybe there are some tricks.如果我们在谈论实例,那么也许有一些技巧。

It is also good practice to think Derived class as a specialization of the Base class, so that common behavior remains in the Base class and you just tweak (aka override) some parameters and methods where it is needed, and for the particular purpose.将 Derived class 视为 Base class 的专业化也是一种很好的做法,因此常见行为仍保留在 Base class 中,您只需调整(也称为覆盖)一些特定目的和方法的参数和方法。 This makes the entire code more readable and maintainable.这使得整个代码更具可读性和可维护性。

For your particular case, I can think of a different solution, where you could embed the scaling directly in your Base class, and change the scaling factor only in your derived classes, something like:对于您的特定情况,我可以想到一个不同的解决方案,您可以将缩放直接嵌入到 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))

All you need to change, in this case, is the self.scaling value in any class you derive from Base .在这种情况下,您需要更改的只是从Base派生的任何 class 中的self.scaling值。 Your real-world scenario might be more complex, but I believe this paradigm would serve you better.您的现实世界场景可能更复杂,但我相信这种范式会更好地为您服务。

There are two approaches you can take.您可以采取两种方法。 First, make scaler a function argument to decode ;首先,将scaler设为 function 参数以进行decode it doesn't need to be a method, because you aren't using its self argument.它不需要是一个方法,因为你没有使用它的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 directly to Building.decode ) (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)

Alternately, define a do-nothing scaling method in Building , and let derived class override it as necessary.或者,在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

Note that in both cases, I've dispensed with overriding methods like __init__ where the derived class did nothing but use super to call the parent method with the same arguments.请注意,在这两种情况下,我都放弃了像__init__这样的重写方法,其中派生的 class 什么都不做,只是使用super调用具有相同 arguments 的父方法。 Inheritance ensures that the parent will be called if no override is defined. Inheritance 确保在未定义覆盖时调用父级。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 从派生类对象python调用基类的方法 - Call method of base class from derived class object python 如何从python中相同的重载派生类方法中调用基类方法? - How do I call a base class method from within the same overloaded derived class method in python? 从基类包装派生类方法 - Wrapping derived class method from base class 如何调用派生的 class 方法? - How to call a derived class method? 派生类重载基类方法时调用它 - Call base class method when derived class overloads it 如何在 python 的派生 class 中调用具有相同名称方法的基本 class 的方法? - How to call a method of base class with same name method in derived class in python? 在Python中从派生类方法调用基类方法 - Calling a base class method from a derived class method in Python 当基类 class 本身继承自另一个库 class (ndb.Model) 时,如何从派生的 class 调用基类 class 的类方法 - How to call classmethod of base class from derived class when base class itself is inheriting from another library class (ndb.Model) 在派生类之外使用派生类对象调用基类方法 - call a base class method using a derived class object outside the derived class 如何从Python中运行调用Thread派生类方法? - How to call Thread derived class method from run in Python?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM