Home | History | Annotate | Download | only in metaclasses
      1 """Generic metaclass.
      2 
      3 XXX This is very much a work in progress.
      4 
      5 """
      6 
      7 import types
      8 
      9 class MetaMethodWrapper:
     10 
     11     def __init__(self, func, inst):
     12         self.func = func
     13         self.inst = inst
     14         self.__name__ = self.func.__name__
     15 
     16     def __call__(self, *args, **kw):
     17         return apply(self.func, (self.inst,) + args, kw)
     18 
     19 class MetaHelper:
     20 
     21     __methodwrapper__ = MetaMethodWrapper # For derived helpers to override
     22 
     23     def __helperinit__(self, formalclass):
     24         self.__formalclass__ = formalclass
     25 
     26     def __getattr__(self, name):
     27         # Invoked for any attr not in the instance's __dict__
     28         try:
     29             raw = self.__formalclass__.__getattr__(name)
     30         except AttributeError:
     31             try:
     32                 ga = self.__formalclass__.__getattr__('__usergetattr__')
     33             except (KeyError, AttributeError):
     34                 raise AttributeError, name
     35             return ga(self, name)
     36         if type(raw) != types.FunctionType:
     37             return raw
     38         return self.__methodwrapper__(raw, self)
     39 
     40 class MetaClass:
     41 
     42     """A generic metaclass.
     43 
     44     This can be subclassed to implement various kinds of meta-behavior.
     45 
     46     """
     47 
     48     __helper__ = MetaHelper             # For derived metaclasses to override
     49 
     50     __inited = 0
     51 
     52     def __init__(self, name, bases, dict):
     53         try:
     54             ga = dict['__getattr__']
     55         except KeyError:
     56             pass
     57         else:
     58             dict['__usergetattr__'] = ga
     59             del dict['__getattr__']
     60         self.__name__ = name
     61         self.__bases__ = bases
     62         self.__realdict__ = dict
     63         self.__inited = 1
     64 
     65     def __getattr__(self, name):
     66         try:
     67             return self.__realdict__[name]
     68         except KeyError:
     69             for base in self.__bases__:
     70                 try:
     71                     return base.__getattr__(name)
     72                 except AttributeError:
     73                     pass
     74             raise AttributeError, name
     75 
     76     def __setattr__(self, name, value):
     77         if not self.__inited:
     78             self.__dict__[name] = value
     79         else:
     80             self.__realdict__[name] = value
     81 
     82     def __call__(self, *args, **kw):
     83         inst = self.__helper__()
     84         inst.__helperinit__(self)
     85         try:
     86             init = inst.__getattr__('__init__')
     87         except AttributeError:
     88             init = lambda: None
     89         apply(init, args, kw)
     90         return inst
     91 
     92 
     93 Meta = MetaClass('Meta', (), {})
     94 
     95 
     96 def _test():
     97     class C(Meta):
     98         def __init__(self, *args):
     99             print "__init__, args =", args
    100         def m1(self, x):
    101             print "m1(x=%r)" % (x,)
    102     print C
    103     x = C()
    104     print x
    105     x.m1(12)
    106     class D(C):
    107         def __getattr__(self, name):
    108             if name[:2] == '__': raise AttributeError, name
    109             return "getattr:%s" % name
    110     x = D()
    111     print x.foo
    112     print x._foo
    113 ##     print x.__foo
    114 ##     print x.__foo__
    115 
    116 
    117 if __name__ == '__main__':
    118     _test()
    119