Last active
June 14, 2020 16:33
-
-
Save JonnyWaffles/dbbb445b174c398909bfb6eab6081497 to your computer and use it in GitHub Desktop.
Demo of how the underlying Python object model works because I always forget and need to re-read it
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class MyMetaClass(type): | |
def __new__(cls, name, bases, attrs): | |
""" | |
Step 1: | |
Called when the module is loaded and class definitions are read. | |
Prepares the new type MyObj. | |
cls is MyMetaclass, name, bases, and attrs is the code | |
in the class definition, aka name, bases, attrs | |
""" | |
print(f'Messagee 1: Hi from meta new') | |
assert name == 'MyObj' | |
assert bases == () | |
assert attrs['cls_attr'] == 'my class attribute' | |
my_obj_cls = super().__new__(cls, name, bases, attrs) | |
return my_obj_cls | |
def __call__(cls, *args, **kwargs): | |
""" | |
Step 2: Called when a child class is instantiated. Consider this a metahook for object creation. | |
args and kwargs are whatever data will eventually be passed to the instances init | |
Args: | |
*args: | |
**kwargs: | |
Returns: | |
""" | |
assert cls is MyObj | |
print(f'Message 3: hi from meta call {args}, {kwargs}') | |
instance = super().__call__(*args, **kwargs) | |
print('Message 6: Return the object instance from meta call') | |
assert isinstance(instance, MyObj) | |
return instance | |
class MyObj(metaclass=MyMetaClass): | |
cls_attr = 'my class attribute' | |
def __new__(cls, *args, **kwargs): | |
"""Creates a new instance of MyObj and | |
then passes it init. | |
Note *args and **kwargs is the same data sent to init | |
""" | |
print('Message 4: hi from MyObj new') | |
assert args == ('arg1', 'arg2') | |
assert kwargs == {'kwarg1': 'val1', 'kwarg2': 'val2'} | |
assert isinstance(cls, MyMetaClass) | |
assert type(cls) is MyMetaClass | |
new = super().__new__ | |
# Under the hood we're using object to create a new instance of cls | |
assert new is object.__new__ | |
# Return an instance of cls so init is triggered | |
instance = new(cls) | |
return instance | |
def __init__(self, *args, **kwargs): | |
print('Message 5: hi from MyObj init') | |
assert args == ('arg1', 'arg2') | |
assert kwargs == {'kwarg1': 'val1', 'kwarg2': 'val2'} | |
print('Message 2: Prior to instantiating MyObj instance') | |
obj = MyObj('arg1', 'arg2', kwarg1='val1', kwarg2='val2') | |
assert isinstance(obj, MyObj) | |
print('Message 7: All one') |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment