【问题标题】:how to factor out common code when metaclass is used使用元类时如何分解公共代码
【发布时间】:2020-12-05 11:56:18
【问题描述】:

我想使用元类来实现一个工厂,该工厂为来自不同来源的数据制造处理器。以下是骨架代码:

class ProcessorFactory

    def __call__(self, classname, supers, classdict):
         ...

    def __New__(self, classname, supers, classdict):
         ...

    def __int__(self):
         ...

class MQ_AddOn(object):
    # MQ-specific code

class File_AddOn(object):
    # Filesystem-specific code

class Web_AddOn(object):
    # Web-specific code

class MQ_Processor(MQ_AddOn, metaclass=ProcessorFactory()):

    # code common to all channels (MQ, Filesystem, Web)

class File_Processor(File_AddOn, metaclass=ProcessorFactory()):

    # code common to all channels (MQ, Filesystem, Web)

class Web_Processor(Web_AddOn, metaclass=ProcessorFactory()):

    # code common to all channels (MQ, Filesystem, Web)

我的问题是,是否有一种方法,类似于汇编中的宏扩展,将所有通道(MQ、文件系统、Web)共有的代码分解出来,这样就不必为每个类复制它?

【问题讨论】:

  • 什么是SorrogateFactory?除非它是一个返回元类的可调用对象,否则您需要metaclass=SorrogateFactory
  • 我猜你的意思是metaclass=ProcessorFactory,而且你似乎把父母弄糊涂了:class File_processor(File_AddOn...)
  • 是的。那是一个错字。它是处理器工厂。修好了。
  • 我对您要排除哪些常见代码感到有些困惑。它只是class 语句的元类部分吗?我对元类是ProcessorFactory 的实例而不是type 的子类(我认为这是不合法的)感到更加困惑。这看起来可能是XY problem

标签: python metaclass


【解决方案1】:

抱歉 - 我认为您必须更多地扩展您的伪代码以获得有意义的答案。

不复制代码的方法是使用 Python 中的常规继承机制 - 如果您有所有这些类共有的代码,只需将该代码放在一个公共基类中,这可能是一个 mixin(即不需要它成为“唯一”基类),并且您已设置。

如果公共代码必须调用特定于每个子类的数据获取或处理方法,只需编写细粒度的方法来执行此操作,并将调用放在公共方法中。

此外,在此过程中不需要“元类”或“内联宏扩展” - 只需使用普通方法和更细粒度的方法即可。


class Base:
    def process(self,...):
         # preparing code
         ...
         # data gather
         data = self.fetch_data()
         # common data pre-processing code:
         ...
         # specific data processing code:
         post_data = self.refine_data(data)
         # more common code
         ...
         # specific output:
         self.output(post_data)

    def fetch_data(self, ...):
        pass
    def refine_data(self, data):
        pass
    def output(self, data):
        pass

然后,在子类上实现那些解决特定通道特性的子类。那里没有什么大秘密。

即使您需要做更多的事情,例如在每个步骤中从多个“叶”类调用的步骤,您最好让您的类具有“管道”数据成员,否则这些步骤是按顺序注释和调用的 - 仍然不需要(也没有意义)涉及元类。

在您的示例中,“Base”类可以适合您提到的所有“通用代码”,并与多重继承一起使用:


class MQProcessor(MQAddOn, Base):
   ...

...

(当您在元类中编写 __call____new__ 方法时,可能会尝试认为“好的 - 这些是可能有意义的元类相关的东西” - 但元类中的 __int__没有意义根本:它会提供一种将类(不是实例,不是某些数据内容)映射到整数的方法 - 即使您将这些类放在列表中,并且它们需要索引要位于列表中,并且您想要交叉引用那些,您应该只向类添加自定义“.index”属性,而不是在元类上写__int__

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-11-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-12-19
    相关资源
    最近更新 更多