代码之家  ›  专栏  ›  技术社区  ›  cap

用于预定义类创建的元类与继承

  •  1
  • cap  · 技术社区  · 7 年前

    class MusicFile(object):
       extension = [""]
    
       def setup(self):
           #set up the data
    
       def runsoftware(self):
           #play the song
    
    class MP3(MusicFile):
       extension = [".mp3"]
    
       def setup(self):
           #setupMP3file
    
       def runsoftware(self):
           #runMP3software
    

    我有大约4个通用类,然后文件扩展名的定义和处理将有所不同。每个类都有其工作所需的已定义数量的方法。目前,只支持一个或两个文件扩展名,但我想保留这样一个结构,即添加更多扩展名对其他人来说很容易(也许是直观的)。

    使用元类是否适合这种情况?为了建立一些严格的类,这些类必须包含我之前定义的方法,这样就可以在所有的类中统一。我应该坚持简单的继承吗?

    我希望能拥有 MusicFile 注册为能够实例化正确的一个(例如,给定一个文件路径)。

    2 回复  |  直到 7 年前
        1
  •  2
  •   Olivier Melançon iacob    7 年前

    这个答案只适用于Python3.6+。如果您可以选择升级到最新的Python版本, there are numerous reasons why you should 下面可能是其中之一。

    __init_subclass__ 在类被子类化之后执行的钩子。

    class MusicFile:
        _register = {}
    
        def __init_subclass__(cls, **kwargs):
            if not hasattr(cls, 'extension'):
                raise ValueError(cls.__name__ + ' has no extension')
    
            MusicFile._register.update({e: cls for e in cls.extension})
    
        @classmethod
        def get_class_by_extension(cls, ext):
            return cls._register.get(ext)
    

    例子

    class MP3(MusicFile):
        extension = ['mp3']
    
    class MIDI(MusicFile):
        extension = ['midi']
    
    MusicFile.get_class_by_extension('mp3') # <class '__main__.MP3'>
    MusicFile.get_class_by_extension('midi') # <class '__main__.MIDI'>
    

    the factory approach suggested by bipll ,但以更直接和可维护的方式。

        2
  •  2
  •   bipll    7 年前

    我希望能够注册MusicFile的所有子类,以便能够实例化正确的子类(例如,给定一个文件路径)。

    a Factory ?

    这个工厂可能可以用元类自动构建。我看到的一个严重问题是使用类自己的 extension

    class MusicFile(object):
        known_types = {}
    
        @staticmethod
        def processor(ext):
            return MusicFile.known_types[ext]()
    
    def file_types(*exts):
        def registered_class(cls):
            for ext in exts: MusicFile.known_types[ext] = cls
            return cls
        return registered_class
    
    @file_types('mp3')
    class Mp3(MusicFile):
        def greet(self):
            print 'Hi .mp3!'
    
    @file_types('mid', 'midi')
    class Midi(MusicFile):
        def greet(self):
            print 'Hi, Music Instruments Digital Interface!'
    
    pcsor = MusicFile.processor('mp3')
    pcsor.greet()                      # Hi .mp3!
    pcsor = MusicFile.processor('mid')
    pcsor.greet()                      # Hi, Music Instruments Digital Interface!
    pcsor = MusicFile.processor('midi')
    pcsor.greet()                      # Hi, Music Instruments Digital Interface!
    pcsor = MusicFile.processor('s3m') # KeyError: 's3m'
    pcsor.greet()