Skip to content

Instantly share code, notes, and snippets.

@ychennay
Last active December 23, 2022 05:46
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ychennay/e3ed251da577306831f677af24677a6e to your computer and use it in GitHub Desktop.
Save ychennay/e3ed251da577306831f677af24677a6e to your computer and use it in GitHub Desktop.
Example of metaclass
class ModelBase(type):
a_variable_from_metaclass = 3
_instances = dict() # keep track of the instances created per class
@classmethod
def __prepare__(metacls, name, bases, **kwargs): # called first
print(f"\nInside MetaClass __prepare__, name: {name}, bases: {bases}, metacls: {metacls}, kwargs: {kwargs}")
namespace = super().__prepare__(name, bases, **kwargs)
print(f"Returned namespace: {namespace}")
return namespace
def __new__(cls, name, bases, namespaces, **kwargs): # called second, and constructs the new class
print(
f"\nInside MetaClass __new__(), name: {name}, bases: {bases}, cls: {cls}, kwargs: {kwargs}, namespaces: {namespaces}")
namespaces["some_variable"] = 5 # setting a variable
for attribute_name, attribute_value in namespaces.items():
# iterate through the provided namespace, and change all the integer values to instances of ModelField
if isinstance(attribute_value, int):
namespaces[attribute_name] = ModelField(attribute_value)
new_class = super().__new__(cls, name, bases, namespaces, **kwargs)
print(f"Output of __new__: {new_class}")
return new_class
def __init__(cls, name, bases, namespace, **kwargs): # called third, initializes the newly created class with values
# By the time __init__ is called, the new class exists
print("\nInside __init__ of MetaClass")
print(f"cls: {cls}, name: {name}, bases: {bases}, namespace: {namespace}, kwargs: {kwargs}")
ModelBase.__setattr__(cls, "some_variable", 4)
cls.variable_added_during_init = "boom"
namespace["some_variable"] = 4 # attempt to change the attribute some_variable's value to 4
super().__init__(name, bases, namespace)
def __call__(cls, *args, **kwargs): # called when new instances are created, delegates initialization to __init__
print(f"Inside __call__ of MetaClass.")
print(f"cls: {cls}, args: {args}, kwargs: {kwargs}")
if cls not in cls._instances: # https://stackoverflow.com/questions/6760685/creating-a-singleton-in-python
cls._instances[cls] = super().__call__(*args, **kwargs)
print(f"Output of __call__: {cls._instances[cls]}")
return cls._instances[cls]
@rongpenl
Copy link

Hi @ychennay. Thank you for creating this. Isn't line 34-36 unnecessary?

@ychennay
Copy link
Author

Hi @ychennay. Thank you for creating this. Isn't line 34-36 unnecessary?

Yes you are right - silly typo. I've removed it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment