mirror of
https://github.com/python/cpython.git
synced 2024-11-30 01:16:51 +01:00
e13be40b88
should have been a NameError. I'm checking in a change that catches both, just to be sure -- I can't be bothered trying to understand this code any more. :-)
121 lines
2.9 KiB
Python
121 lines
2.9 KiB
Python
"""Generic metaclass.
|
|
|
|
XXX This is very much a work in progress.
|
|
|
|
"""
|
|
|
|
import types
|
|
|
|
class MetaMethodWrapper:
|
|
|
|
def __init__(self, func, inst):
|
|
self.func = func
|
|
self.inst = inst
|
|
self.__name__ = self.func.__name__
|
|
|
|
def __call__(self, *args, **kw):
|
|
return apply(self.func, (self.inst,) + args, kw)
|
|
|
|
class MetaHelper:
|
|
|
|
__methodwrapper__ = MetaMethodWrapper # For derived helpers to override
|
|
|
|
def __helperinit__(self, formalclass):
|
|
self.__formalclass__ = formalclass
|
|
|
|
def __getattr__(self, name):
|
|
# Invoked for any attr not in the instance's __dict__
|
|
try:
|
|
raw = self.__formalclass__.__getattr__(name)
|
|
except AttributeError:
|
|
try:
|
|
ga = self.__formalclass__.__getattr__('__usergetattr__')
|
|
except (KeyError, AttributeError):
|
|
raise AttributeError, name
|
|
return ga(self, name)
|
|
if type(raw) != types.FunctionType:
|
|
return raw
|
|
return self.__methodwrapper__(raw, self)
|
|
|
|
class MetaClass:
|
|
|
|
"""A generic metaclass.
|
|
|
|
This can be subclassed to implement various kinds of meta-behavior.
|
|
|
|
"""
|
|
|
|
__helper__ = MetaHelper # For derived metaclasses to override
|
|
|
|
__inited = 0
|
|
|
|
def __init__(self, name, bases, dict):
|
|
try:
|
|
ga = dict['__getattr__']
|
|
except KeyError:
|
|
pass
|
|
else:
|
|
dict['__usergetattr__'] = ga
|
|
del dict['__getattr__']
|
|
self.__name__ = name
|
|
self.__bases__ = bases
|
|
self.__realdict__ = dict
|
|
self.__inited = 1
|
|
|
|
def __getattr__(self, name):
|
|
try:
|
|
return self.__realdict__[name]
|
|
except KeyError:
|
|
for base in self.__bases__:
|
|
try:
|
|
return base.__getattr__(name)
|
|
except AttributeError:
|
|
pass
|
|
raise AttributeError, name
|
|
|
|
def __setattr__(self, name, value):
|
|
if not self.__inited:
|
|
self.__dict__[name] = value
|
|
else:
|
|
self.__realdict__[name] = value
|
|
|
|
def __call__(self, *args, **kw):
|
|
inst = self.__helper__()
|
|
inst.__helperinit__(self)
|
|
try:
|
|
init = inst.__getattr__('__init__')
|
|
except AttributeError:
|
|
init = lambda: None
|
|
apply(init, args, kw)
|
|
return inst
|
|
|
|
|
|
Meta = MetaClass('Meta', (), {})
|
|
|
|
|
|
def _test():
|
|
class C(Meta):
|
|
def __init__(self, *args):
|
|
print "__init__, args =", args
|
|
def m1(self, x):
|
|
print "m1(x=%s)" %`x`
|
|
print C
|
|
x = C()
|
|
print x
|
|
x.m1(12)
|
|
class D(C):
|
|
def __getattr__(self, name):
|
|
if name[:2] == '__': raise AttributeError, name
|
|
return "getattr:%s" % name
|
|
x = D()
|
|
print x.foo
|
|
print x._foo
|
|
## print x.__foo
|
|
## print x.__foo__
|
|
|
|
|
|
if __name__ == '__main__':
|
|
_test()
|
|
|
|
|