This metaclass generates an __slot__ attribute automatically by examining the __init__ function of a class.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 | import inspect, _ast
class Autoslots_meta(type):
"""
Looks for assignments in __init__
and creates a __slot__ variable for all the
instance attributes in the assignment.
Assumes that all assignments in __init__ are of
the form:
self.attr = <value>
"""
def __new__(cls, name, bases, dct):
slots = dct.get('__slots__', [])
orig_slots = []
for base in bases:
if hasattr(base, "__slots__"):
orig_slots += base.__slots__
if '__init__' in dct:
init = dct['__init__']
initproc = type.__new__(cls, name, bases, dct)
initproc_source = inspect.getsource(initproc)
ast = compile(initproc_source, "dont_care", 'exec', _ast.PyCF_ONLY_AST)
classdef = ast.body[0]
stmts = classdef.body
for declaration in stmts:
if isinstance(declaration, _ast.FunctionDef):
name1 = declaration.name
if name1 == '__init__': # delete this line if you do not initialize all instance variables in __init__
initbody = declaration.body
for statement in initbody:
if isinstance(statement, _ast.Assign):
for target in statement.targets:
name1 = target.attr
if name1 not in orig_slots:
slots.append(name1)
if slots:
dct['__slots__'] = slots
return type.__new__(cls, name, bases, dct)
class Autoslots(object):
__metaclass__ = Autoslots_meta
class TestClass(Autoslots):
def __init__(self):
self.a = 1
self.b = 2
def t(self):
pass
|
This is a variant of recipe 435880 (http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/435880). It examines the __init__ method for assignments of the form:
self.attribute = value
and adds attrbute to the class variable __slot__.
Class TestClass shows how to use this metaclass: you inherit from Autoslots.
Tags: shortcuts