When a class object is created, normally the class body is exec'ed first and then the class object is generated with that resulting namespace.
This recipe lets you flip that around, and then make the class object available to the class body during execution.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | """class_hack module"""
from functools import wraps
class Body:
def __body__(cls):
"""Generate the class body."""
return locals()
class BodyMeta(type):
def __new__(meta, name, bases, namespace):
body = namespace.pop("__body__", None)
cls = type.__new__(meta, name, bases, namespace)
if body:
arg = body.__code__.co_varnames[:body.__code__.co_argcount][0]
@wraps(body)
def __body__(cls):
return dict((k, v) for k, v in body(cls).items() if k != arg)
for key, value in __body__(cls).items():
setattr(cls, key, value)
setattr(cls, "__body__", staticmethod(__body__))
return cls
|
Example
class Something(metaclass=BodyMeta):
def __body__(cls):
"some doc"
#class body goes here
def __init__(self, name):
self._name = name
@property
def name(self):
return self._name
return locals()
print(Something.__init__)
# <function __init__ at ...>
print(Something.name)
# <property object at ...>
print(Something.__body__)
# <function __body__ at ...>
print(Something("Bob").name)
# Bob