|
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() |