Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
building classes in python
def sample_1(parent=object):
class Sample(parent):
def __init__(self, val=None):
self.value = val
return Sample
def sample_2(parent=object):
class Sample(parent):
def __init__(self, val=None):
super().__init__(self)
self.value = val
return Sample
from dis import dis, show_code
from types import CodeType
def disassemble(obj, verbose=False):
if verbose:
show_code(obj)
print("Disassembly:")
dis(obj)
def find_code_const(obj, name):
obj = getattr(obj, "__code__", obj)
for c in obj.co_consts:
if isinstance(c, CodeType):
if c.co_name == name:
return c
else:
return None
# Sample1 = sample_1(object)
Sample1_class_code = find_code_const(sample_1, "Sample")
Sample1_init_code = find_code_const(Sample1_class_code, "__init__")
# Sample2 = sample_2(object)
Sample2_class_code = find_code_const(sample_2, "Sample")
Sample2_init_code = find_code_const(Sample2_class_code, "__init__")
if __name__ == "__main__":
print("\n === Sample1 class code ===")
disassemble(Sample1_class_code, True)
print("\n === Sample1 init code ===")
disassemble(Sample1_init_code, True)
print("\n === Sample2 class code ===")
disassemble(Sample2_class_code, True)
print("\n === Sample2 init code ===")
disassemble(Sample2_init_code, True)
# yuck.
@obriencj

This comment has been minimized.

Copy link
Owner Author

obriencj commented May 6, 2018

Here's a side-by-side comparison of the Sample1 class and init code disassemblies
https://gist.github.com/obriencj/a32ad3de87487e4ee731625633f35aa0/revisions?diff=split

Here's how that __classcell__ closure is consumed by the type() call
https://github.com/python/cpython/blob/b1c70d0ffbb235def1deab62a744ffd9b5253924/Objects/typeobject.c#L2690

@obriencj

This comment has been minimized.

Copy link
Owner Author

obriencj commented May 6, 2018

This is how the python 3.6 variation of a no-argument super() was implemented. When detected at compile time, it causes the compiler to inject a closure for a value named __class__ into any method code which uses the super. That __class__ closure is then captured in the class' namespace as the __classcell__. The type() call which creates a type from the namespace resulting from calling the class code will check for the cell in a __classcell__ attribute, and if it finds one, will set the cell contents to the resulting class instance that type has created.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.