blob: 90bfd97d6e003e057d8f20504f3cb515ccfbf646 [file] [log] [blame]
Guido van Rossum27e4aa31997-08-25 15:37:59 +00001"""Generic metaclass.
2
3XXX This is very much a work in progress.
4
5"""
6
7import types
8
9class MetaMethodWrapper:
10
11 def __init__(self, func, inst):
Guido van Rossum4117e541998-09-14 16:44:15 +000012 self.func = func
13 self.inst = inst
14 self.__name__ = self.func.__name__
Guido van Rossum27e4aa31997-08-25 15:37:59 +000015
16 def __call__(self, *args, **kw):
Neal Norwitzd9108552006-03-17 08:00:19 +000017 return self.func(self.inst, *args, **kw)
Guido van Rossum27e4aa31997-08-25 15:37:59 +000018
19class MetaHelper:
20
21 __methodwrapper__ = MetaMethodWrapper # For derived helpers to override
22
23 def __helperinit__(self, formalclass):
Guido van Rossum4117e541998-09-14 16:44:15 +000024 self.__formalclass__ = formalclass
Guido van Rossum27e4aa31997-08-25 15:37:59 +000025
26 def __getattr__(self, name):
Guido van Rossum4117e541998-09-14 16:44:15 +000027 # 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__')
Guido van Rossume13be402001-01-15 16:53:58 +000033 except (KeyError, AttributeError):
Collin Winter6f2df4d2007-07-17 20:59:35 +000034 raise AttributeError(name)
Guido van Rossum4117e541998-09-14 16:44:15 +000035 return ga(self, name)
36 if type(raw) != types.FunctionType:
37 return raw
38 return self.__methodwrapper__(raw, self)
Guido van Rossum27e4aa31997-08-25 15:37:59 +000039
40class MetaClass:
41
42 """A generic metaclass.
43
44 This can be subclassed to implement various kinds of meta-behavior.
45
46 """
47
Guido van Rossum4117e541998-09-14 16:44:15 +000048 __helper__ = MetaHelper # For derived metaclasses to override
Guido van Rossum27e4aa31997-08-25 15:37:59 +000049
50 __inited = 0
51
52 def __init__(self, name, bases, dict):
Guido van Rossum4117e541998-09-14 16:44:15 +000053 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
Guido van Rossum27e4aa31997-08-25 15:37:59 +000064
65 def __getattr__(self, name):
Guido van Rossum4117e541998-09-14 16:44:15 +000066 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
Collin Winter6f2df4d2007-07-17 20:59:35 +000074 raise AttributeError(name)
Guido van Rossum27e4aa31997-08-25 15:37:59 +000075
76 def __setattr__(self, name, value):
Guido van Rossum4117e541998-09-14 16:44:15 +000077 if not self.__inited:
78 self.__dict__[name] = value
79 else:
80 self.__realdict__[name] = value
Guido van Rossum27e4aa31997-08-25 15:37:59 +000081
82 def __call__(self, *args, **kw):
Guido van Rossum4117e541998-09-14 16:44:15 +000083 inst = self.__helper__()
84 inst.__helperinit__(self)
85 try:
86 init = inst.__getattr__('__init__')
87 except AttributeError:
88 init = lambda: None
Neal Norwitzd9108552006-03-17 08:00:19 +000089 init(*args, **kw)
Guido van Rossum4117e541998-09-14 16:44:15 +000090 return inst
Tim Peterse6ddc8b2004-07-18 05:56:09 +000091
Guido van Rossum27e4aa31997-08-25 15:37:59 +000092
93Meta = MetaClass('Meta', (), {})
94
95
96def _test():
97 class C(Meta):
Guido van Rossum4117e541998-09-14 16:44:15 +000098 def __init__(self, *args):
Collin Winter6f2df4d2007-07-17 20:59:35 +000099 print("__init__, args =", args)
Guido van Rossum4117e541998-09-14 16:44:15 +0000100 def m1(self, x):
Collin Winter6f2df4d2007-07-17 20:59:35 +0000101 print("m1(x=%r)" % (x,))
102 print(C)
Guido van Rossum27e4aa31997-08-25 15:37:59 +0000103 x = C()
Collin Winter6f2df4d2007-07-17 20:59:35 +0000104 print(x)
Guido van Rossum27e4aa31997-08-25 15:37:59 +0000105 x.m1(12)
Guido van Rossum1fb071c1997-08-25 21:36:44 +0000106 class D(C):
Guido van Rossum4117e541998-09-14 16:44:15 +0000107 def __getattr__(self, name):
Collin Winter6f2df4d2007-07-17 20:59:35 +0000108 if name[:2] == '__': raise AttributeError(name)
Guido van Rossum4117e541998-09-14 16:44:15 +0000109 return "getattr:%s" % name
Guido van Rossum1fb071c1997-08-25 21:36:44 +0000110 x = D()
Collin Winter6f2df4d2007-07-17 20:59:35 +0000111 print(x.foo)
112 print(x._foo)
Guido van Rossum1fb071c1997-08-25 21:36:44 +0000113## print x.__foo
114## print x.__foo__
115
Guido van Rossum27e4aa31997-08-25 15:37:59 +0000116
117if __name__ == '__main__':
118 _test()