0
0
mirror of https://github.com/python/cpython.git synced 2024-11-30 01:16:51 +01:00
cpython/Demo/metaclasses/Meta.py
Guido van Rossum e13be40b88 Geoffrey Gerrietts discovered that a KeyError was caught that probably
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. :-)
2001-01-15 16:53:58 +00:00

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