What is Python Metaprogramming

Emmanuel Lodovice
Uncaught Exception
Published in
2 min readFeb 3, 2019

Instances are created by special objects called “classes”. This means that classes are also objects and can be modified like how we modify instances, the only difference is that if we modify a class it affects all instances created from the class.

>>> class Foo:
>>> pass
>>> firstFoo = Foo()
>>> Foo.bar = 1
>>> print(firstFoo.bar)
1
>>> secondFoo = Foo()
>>> print(secondFoo.bar)
1
>>> secondFoo.a = 1
>>> print(secondFoo.a)
1
>>> print(firstFoo.a)
AttributeError: Foo instance has no attribute 'a'

If instances are created by classes, classes are created by special objects called “metaclasses”. Metaprogramming is when you modify how classes are created using metaclasses.

How?

The default metaclass istype and it is what’s normally used to create the classes that you write.

class Foo:
pass

is the same as:

Foo = type('Foo', (), {})

and

>>> class B(list):
>>> x = 1

>>> def hi(self, name):
>>> print('hi', name)
>>> def hii(self, name):
>>> print('hi', name)
>>> def fake_init(self):
>>> print('Fake init')
>>> C = type('C', (list,), {'x': 1, 'hii': hii, '__init__': fake_init})>>> b = B()
1
>>> b.append(1)
>>> print(b.x)
1
>>> b.hi('B')
('hi', 'B')
>>> c = C()
Fake init
>>> c.append(1)
>>> print(c.x)
1
>>> c.hii('C')
('hi', 'C')

The code above displays how we can use a metaclass (“type” in this case) to create classes. Metaprogramming works by adding your own operations into the creation of classes by making a subclass of the type metaclass and inserting it into the process of creating classes through “metaclass hook”.

In python 3, metaclass hook is the metaclass keyword argument in the base-class list of the class definition. If you pass a class as a keyword argument in the base-class list in your class definition class B(metaclass=MyMetaClass): python will call it after the initial creation of the class passing in the class object, class name, list of base classes, and the namespace dictionary.

>>> def custom_func(self):
>>> print('Yeeehaaa')
>>> class MyMetaClass(type):
>>> def __init__(cls, name, base_classes, namespace):
>>> super(MyMetaClass, cls).__init__(name, base_classes, namespace)
>>> cls.custom_func = custom_func
>>> class FooBar(metaclass=MyMetaClass):
>>> pass
>>> bar = FooBar()
>>> bar.custom_func()
Yeeehaaa

That is the basics of metaprogramming. Thanks for reading :)

Reference: https://python-3-patterns-idioms-test.readthedocs.io/en/latest/Metaprogramming.html

--

--