创建基于类的可重用应用程序

时间:2015-10-26 11:09:29

标签: python multiple-inheritance mixins python-2.x code-reuse

我正在尝试在python 2.6中创建一个可重用的应用程序。

我正在开发用于收听GPS跟踪设备的服务器端脚本。该脚本使用套接字。

我有一个基类,它定义了处理设备发送的数据的基本方法。

class MyDevice(object):
    def __init__(self, db)
        self.db = db  # This is the class that defines methods for connecting/using database

    def initialize_db(self):
        ...

    def handle_data(self):
        self.initialize_db()
        ...
        self.process_data()

    def process_data(self):
        ...
        self.categorize_data()

    def categorize_data(self):
        ...
        self.save_data()

    def save_data(self):
        ...

此基类适用于许多设备,因为设备之间只有一些细微差别。因此,我为每个特定的设备类型创建了一个类,并进行了特定于该设备的安排。

class MyDeviceType1(Mydevice):
    def __init__(self, db):
        super(MyDeviceType1, self).__init__(db)

    def categorize_data(self):
        super(MyDeviceType1, self).categorize_data(self)
        self.prepopulate_data()
        ...  # Do other operations specific to device

    def prepopulate_data(self):
        """this is specific to Type1 devices"""
        ...


class MyDeviceType2(Mydevice):
    def __init__(self, db):
        super(MyDeviceType1, self).__init__(db)

    def categorize_data(self):
        super(MyDeviceType1, self).categorize_data(self)
        self.unpopulate_data()
        ...  # Do other operations specific to device

    def unpopulate_data(self):
        """this is specific to Type2 devices"""
        ...

我有侦听特定套接字的套接字侦听器,并调用相关类(MyDeviceType1MyDeviceType2),如:

conn, address = socket.accept()
...
thread.start_new_thread(MyDeviceType1(db_connector).handle_data, ())

这个结构对我来说都很好,也很有用。一个设备( MyDevice )可能有许多子类型( MyDeviceType1 MyDeviceType2 ),它们继承了基类。

并且有多种类型的基本设备。所以 OtherDevice 包含子类型 OtherDeviceType1 等。

MyDeviceOtherDevice的工作原理完全不同,因此它们是基本类型,底层代码在所有这些类型中都有很大不同。

我也有一些附加功能。这些功能可用于几乎所有设备基类型的一个或两个子类型。

所以我想准备一个可重用(可插入)的类,它可以由任何需要这些功能的子类继承。

class MyAddOn(object):
    def remove_unusable_data(self):
       ...

    def categorize_data(self):
        super ???
        self.remove_unusable_data()

这是我卡住的部分。由于这是一个独立的模块,因此不应继承MyDeviceOtherDevice等,但并非所有子设备类型都使用这些功能,我无法从{{1}继承MyDevice也是。

只有逻辑方法,从MyAddOnMyDeviceSubType1继承子类型MyDevice

MyAddOn

class MyDeviceType1(Mydevice, MyAddOn): def __init__(self, db): super(MyDeviceType1, self).__init__(db) def categorize_data(self): >> super(MyDeviceType1, self).categorize_data(self) << self.prepopulate_data() ... # Do other operations specific to device def prepopulate_data(self): """this is specific to Type1 devices""" 是问题的一部分。 super(MyDeviceType1, self).categorize_data(self)正在触发super但不会触发Mydevice.categorize_data

有没有办法使用MyAddOn.categorize_data调用触发MyAddOn方法,或者我不需要单独调用该类方法?应该调用superMyDevice.categorize_data

1 个答案:

答案 0 :(得分:2)

这在python中称为协作多重继承,并且工作得很好。

您所谓的“Addon”类通常称为“Mixin”。

只需调用Mixin类中的super方法:

class MyAddOn(object):
    def remove_unusable_data(self):
       ...

    def categorize_data(self):
        super(MyAddon,self).categorize_data()
        self.remove_unusable_data()

我想注意一些事情:

  • 方法解析顺序从左到右
  • 你必须打电话给超级
  • 你应该使用** kwargs进行合作继承

在此处调用super似乎违反直觉,因为MyAddon的父级没有名为categorize_data的属性,并且您希望此注释失败。

这是super功能发挥作用的地方。 Some认为这种行为是python的最佳选择。

C ++ Java 不同,super函数不一定会调用类的父类。事实上,不可能事先知道super将调用哪个函数,因为它将在运行时基于method resoltion order来确定。

python中的

super应该被称为next,因为它将调用继承树中的下一个方法。

对于Mixins,即使你继承自object,调用super也特别重要。

有关详细信息,我建议观看Raymond Hettinger在2015年pycon Super considered Super上的精彩演讲。

这是在python中使用的优秀模式。这是我在编写符合open-closed principle

的结构化应用程序时经常遇到的模式

我有这个用于生产的库类:

class BaseClassA(object):
   def __init__(self, **kwargs):
       ... Do something that's important for many modules
   def ...   

class BaseClassB(object):
   def __init__(self, **kwargs):
       ... Do something that's important for many modules
   def ...   

现在您收到一个功能请求,在特定情况下,BaseClassABaseClassB都应实现功能X.

根据开放式关闭,您不必触及现有代码来实现该功能,并且根据DRY,您不应该重复该代码。

解决方案是创建一个FeatureMixin并创建从子类和mixin继承的空子类:

class FeatureMixin(object):
    def __init__(self,**kwargs):
        ...do something specific
        return super(FeatureMixin,self).__init__(**kwargs)
class ExtendedA(FeatureMixin,BaseClassA):
   pass
class ExtendedB(FeatureMixin,BaseClassB):
   pass
相关问题