Python从任意类继承方法

时间:2019-06-24 14:39:23

标签: python class

我确定这将是一个重复的问题,但我似乎找不到找到该单词的词。

我要编写一组非常相似的模型。除了单个功能/代码行外,模型都是相同的。我想避免任何代码重复。让我们看一下MWE:

import numpy as np

class SinModel:   
    def __init__(self):
        self.x = np.linspace(-np.pi, np.pi)
    def run(self):
        # Computations which are invariant of the function we use later
        self.y = np.sin(self.x)
        # More computations which are invariant of which funcion was used

我们的第二个模型将涉及相同的一系列计算,但是会在途中使用不同的函数(这里用余弦代替正弦):

class CosModel:
    def __init__(self):
        self.x = np.linspace(-np.pi, np.pi)
    def run(self):
        # Computations which are the same as in SinModel
        self.y = np.cos(self.x)
        # More computations which are the same as in SinModel

这里我有很多重复代码。有没有更好的方法来实现这些模型?我希望可以创建一个类Model,该类可以继承任意类的不同功能。

重要的一点是,根据模型的不同,在模型之间更改的函数可能会采用与self不同的参数。

2 个答案:

答案 0 :(得分:2)

您要查找的词是继承(允许类继承和扩展/专门化父类)和“模板方法”设计模式(这可能是最常见的设计模式-每个人自己发现的一种)在了解设计模式之前很久。

扩展您的MWE:

import numpy as np

class ModelBase(object):
    def __init__(self):
        self.x = np.linspace(-np.pi, np.pi)

    def run(self):
        # Computations which are invariant of the function we use later

        self.y = self.compute_y()

        # More computations which are invariant of which funcion was used


    def compute_y(self):
        raise NotImplementedError("class {} must implement compute_y()".format(type(self).__name__))



class SinModel(ModelBase):   
    def compute_y(self):
        return np.sin(self.x)

class CosModel(ModelBase):
    def compute_y(self):
        return np.cos(self.x)

这就是说,在初始化程序之外创建实例属性(__init__方法)被认为是不好的做法-当初始化程序返回时,应完全初始化对象(定义了所有属性),这样可能会更好尽可能将self.y = self.compute_y()行移至初始化程序,或者,如果self.y始终仅依赖于self.x,请将其设置为计算属性:

class ModelBase(object):
    def __init__(self):
        self.x = np.linspace(-np.pi, np.pi)

    @property
    def y(self):
        return self._compute_y()

    def _compute_y(self):
        raise NotImplementedError("class {} must implement _compute_y()".format(type(self).__name__))


    def run(self):
        # Computations which are invariant of the function we use later

        # no need to explicitely set self.y here, just use `self.y`
        # and it will delegate to self._compute_y() 
        #(you can't set it anymore anyway since we made it a readonly propery) 

        # More computations which are invariant of which funcion was used



class SinModel(ModelBase):   
    def _compute_y(self):
        return np.sin(self.x)

class CosModel(ModelBase):
    def _compute_y(self):
        return np.cos(self.x)

在这一点上,您现在不必再需要子类了,至少如果这是唯一要更改的子类,则可以将适当的函数作为回调传递给模型类,即:

class Model(object):
    def __init__(self, compute_y):
        self.x = np.linspace(-np.pi, np.pi)
        self._compute_y = compute_y

    @property
    def y(self):
        return self._compute_y(self)

    def run(self):
       # code here


cos_model = Model(lambda obj: np.cos(obj.x))
cos_model.run()

sin_model = Model(lambda obj: np.sin(obj.x))
sin_model.run()

答案 1 :(得分:0)

是的,甚至有个名字: Inheritance 是子类可以从父类“继承”行为和属性的想法,而 Polymorphism 是这个想法两个具有相似行为的子类可以对同一方法进行不同的实现-因此,您可以在不明确知道对象是什么类型的情况下在对象上调用方法,并且仍然可以做正确的事情。

这是您在python中执行的操作:

class TrigModel:
    def __init__(self):
        self.x = np.linspace(-np.pi, np.pi)
    def run(self):
        raise NotImplementedError("Use subclasses SinModel or CosModel")

class SinModel(TrigModel):
    @override
    def run(self):
        self.y = np.sin(self.x)

class CosModel(TrigModel):
    @override
    def run(self):
        self.y = np.cos(self.x)

除非您另外明确指定(通过声明类似run()的方法来覆盖父类的同名方法,例如SinModel),CosModelTrigModel将自己调用TrigModel的方法(在这种情况下,它们都调用run()的构造函数,但是当您在它们上调用model.run() 时显示不同的行为)。

如果您这样做:

model

然后SinModel的行为会有所不同,具体取决于它是CosModel还是@override,具体取决于您预先设置的内容。

<rule name="welcome2020" stopProcessing="true"> <match url="welcome2020" /> <action type="Redirect" url="https://www.mywebsite.org/Pages/.welcome2020aspx" appendQueryString="false" /> </rule> <rule name="Page to Page Redirect"> <match url="/Staff/Pages/Ashley.aspx" /> <action type="Rewrite" url="services/Staff/Pages/Ashley.aspx" /> </rule> 装饰器不是严格必需的,但是减少歧义是一个好习惯。