Skip to content Skip to sidebar Skip to footer

Metaclass Vs Inheritance For Predefined Class Creation

I'm writing some code for a program that will be able to run some software, read the inputs/outputs and do some data processing along the way. For example: (this is not the real ca

Solution 1:

This answer only applies for Python 3.6+. If you have the option to upgrade to the most recent Python version, there are numerous reasons why you should and the following may be one of them.

Python 3.6 introduced the __init_subclass__ hook that is exectued after a class is subclassed.

classMusicFile:
    _register = {}

    def__init_subclass__(cls, **kwargs):
        ifnothasattr(cls, 'extension'):
            raise ValueError(cls.__name__ + ' has no extension')

        MusicFile._register.update({e: cls for e in cls.extension})

    @classmethoddefget_class_by_extension(cls, ext):
        return cls._register.get(ext)

Example

classMP3(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'>

Note that this is very similar to the factory approach suggested by bipll, but in a more straightforward and maintainable way.

Solution 2:

I want to be able to maybe have all the subclasses of MusicFile registered to be able to instantiate the right one (given a file path, for example).

So you probably want to implement a Factory?

This factory can probably be auto-built with metaclasses. One serious issue I see is using class's own extension member to register it, so to me, it is easier done with metaclasses' eternal competition, decorators:

classMusicFile(object):
    known_types = {}

    @staticmethoddefprocessor(ext):
        return MusicFile.known_types[ext]()

deffile_types(*exts):
    defregistered_class(cls):
        for ext in exts: MusicFile.known_types[ext] = cls
        return cls
    return registered_class

@file_types('mp3')classMp3(MusicFile):
    defgreet(self):
        print'Hi .mp3!'@file_types('mid', 'midi')classMidi(MusicFile):
    defgreet(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()

Post a Comment for "Metaclass Vs Inheritance For Predefined Class Creation"