I am looking for advice on the design of my code.
Introduction
I have several classes, each of which represents a single file type, for example: MediaImageFile, MediaAudioFile and the common (as well as the base class) MediaGenericFile.
Each file has two options: "Wizard" and "Version", so I created these classes to determine their specific behavior. EDIT: The version represents a resized / cropped / cropped / etc version of the main file. It was mainly used for preview.
EDIT: The reason I want to do this dynamically is because this application should be reusable (this is a Django application), and therefore it should be easy to implement another subclass of MediaGenericFile without changing the source code.
What i want to do
First of all, the user should be able to register their own subclasses of MediaGenericFile without affecting the original code.
Whether a version file or a wizard is available (one regular expression) recognized from the file name.
/path/to/master.jpg -- master /path/to/.versions/master_version.jpg -- version
The Master / Version classes use some MediaGenericFile methods / properties, such as the file name (you need to know the file name to create a new version).
MediaGenericFile extends LazyFile, which is just a lazy file object.
Now I need to connect it ...
Used design
Before starting the encoding of the “versions”, I had a factory class MediaFile, which returns a class of the corresponding file type according to the extension:
>>> MediaFile('path/to/image.jpg') <<< <MediaImageFile 'path/to/image.jpg'>
The Master and Version classes define new methods that use the methods and attributes of MediaGenericFile, etc.
Approach 1
One approach is to create a dynamically new type that inherits from Master (or Version) and MediaGenericFile (or a subclass).
class MediaFile(object): def __new__(cls, *args, **kwargs): ...
Approach 2
The second approach is to create the "contrib_to_instance" method in Master / Version and call it after creating new_class, but this is more complicated than I thought:
classs Master(object): @classmethod def contribute_to_instance(cls, instance): methods = (...) for m in methods: setattr(instance, m, types.MethodType(getattr(cls, m), instance)) class MediaFile(object): def __new__(*args, **kwargs): ...
However, this does not work. There are still problems with calling Master / Version methods.
Questions
What would be a good way to implement this multiple inheritance?
What is the name of this problem? :) I tried to find some solutions, but I just don’t know what to name this problem.
Thanks in advance!
Answer Note
larsmans ad
Comparing and checking the instance will not be a problem for my case, because:
In any case, comparisons are overridden.
class MediaGenericFile(object): def __eq__(self, other): return self.name == other.name
I never need to check isinstance (MediaGenericFileVersion, instance). I use isinstance (MediaGenericFile, instance) and isinstance (Version, instance), and both work as expected.
However, creating a new type for an instance sounds to me like a significant defect.
Well, I could dynamically create both variants in a metaclass and then use them, for example:
>>> MediaGenericFile.version_class <<< <class MediaGenericFileVersion> >>> MediaGenericFile.master_class <<< <class MediaGenericFileMaster>
And then:
class MediaFile(object): def __new__(cls, *args, **kwargs): ...
Final decision
Finally, a factory design template. Subclasses of MediaGenericFile are statically typed, users can implement and register their own. Wizard / version variants are dynamically created (glued from several mixins) in the metaclass and stored in the cache to avoid the dangers noted by larsmans.
Thanks to everyone for their suggestions. Finally, I understand the concept of a metaclass. Well, at least I think I understand that. Click the starter wizard ...