I've also used metaclasses in the past to apply a decorator to certain methods of all subclasses, without needing to specify that decorator in the subclass declaration itself.
The user of the utility write this:
class Book(objects.Object):
title: Optional[str]
And the generated class code is: class Book(Base):
__slots__ = ('title', )
title: typing.Optional[str]
def __init__(self, title=None):
self.title = title
@classmethod
def from_data(cls, data):
title = data.get('title', None)
return cls(title=title)
def to_data(self):
data = {}
if self.title is not None:
data['title'] = self.title
return data
@classmethod
def from_oracle_object(cls, obj):
return cls(title=obj.title)
def to_oracle_object(self, connection):
obj = connection.gettype('Book').newobject()
obj.title = self.title
return obj
[1]https://github.com/domingues/oracle-object-mappingAnother example is the builtin "Typing" module where the type system is used to provide a language for representing itself. "Union" itself is a type, and metaclasses allow you to set "__getitem__" on the "Union" type such that Union[Int|Str] is valid and represents a new type. Not that I don't know if metaclasses are actually used to build this system internally, but you could use it for many of the features implemented by Typing.
There are alternative ways to go about doing that because Python is so flexible, but IMO metaclasses (or __init_subclass__ as seen in this post) are the least "magic" of the magic ways to tackle problems like these.
Interestingly _SpecialForm uses a mixin _Final to prevent subclassing. This mixin is made using __init_subclass__
By creating an IrcMessageHandler metaclass, I can easily subclass it to encapsulate functionality into different classes without having to add boilerplate to load each plugin. There's a Plugins directory with a __init__.py that automatically loads all .py files, and the main bot just has to do `from Plugins import *` to load them all. Each plugin script merely needs a `from ircbot import IrcMessageHandler`, then creates a subclass. So there's a Calc class that adds a "!calc" command, Seen class that adds "!seen", and more. Each of them merely needs to include an "on_message" function that parses IRC messages.
To understand this fully you should try to understand how 'type' is the class of a class (which is also an object in python) and you should read how 'type' creates a new class, which is basically the job of your new metaclass should you create one.
Usually you don't need it. Also it's finicky to get right.
Something like __init_subclass__ has a more specific purpose, which I suppose is good. However it also sounds like the kind of thing you probably shouldn't be doing.
https://stackoverflow.com/questions/392160/what-are-some-con...