Thu 21 Nov 2019

Metaclasses

This is a the class of a class. You might use it to generate classes.

Usually you should ignore metaclasses and use class decorators instead. They are for tricky metaprogramming for exceptional scenarios only.

type is dual-purpose:

  1. Tells you what type an object is.
  2. Generates new classes (it's the default metaclass).

str and int also act as metaclasses.

type("className", (parent_class_1, parent_class_2), {"class_attribute": 1})

To create your own metaclass, inherit from type:

class MyMetaClass(type):
    def __new__(cls, clsname, bases, dct, attr_prefix="prefix_goes_here_"):
	"""
	The `__new__` function is what actually creates the object
	that is passed to `__init__` as `self`.

	This metaclass prepends the value of `attr_prefix` to every
	attribute in the classes that use it.
	"""
	modified_attrs = {
	    f"{attr_prefix}{k}": v
	    for k, v in dct.items()
	}

	return super(MyMetaClass, cls).__new__(cls, clsname, bases, modified_attrs)

To use it:

class MyClass(object, metaclass=MyMetaClass, attr_prefix="hello_"):
    you = "x"

dir(MyClass())
['__class__',
'__delattr__',
'__dict__',
'__dir__',
'__doc__',
'__eq__',
'__format__',
'__ge__',
'__getattribute__',
'__gt__',
'__hash__',
'__init__',
'__init_subclass__',
'__le__',
'__lt__',
'__module__',
'__ne__',
'__new__',
'__reduce__',
'__reduce_ex__',
'__repr__',
'__setattr__',
'__sizeof__',
'__str__',
'__subclasshook__',
'__weakref__',
'hello___module__',
'hello___qualname__',
'hello_you']