下面的代码可以让我跟随元类如何工作的操作。但是,当第 21 和 22 行未注释时,Metaclass.__init__
将失败,因为self
参数未传递给包装的方法。是什么导致VerboseFunction.__call__
没有将所需的Metaclass
实例传递给初始化程序?
import sys, types
def sign(prefix, argcount=None):
f = sys._getframe(1)
print('{}.{}({})\n'.format(prefix, f.f_code.co_name,
', '.join(repr(f.f_locals[name])
for name in f.f_code.co_varnames[:f.f_code.co_argcount
if argcount is None else min(argcount, f.f_code.co_argcount)])))
class VerboseMetaclass(type):
def __new__(cls, name, bases, classdict):
sign('VerboseMetaclass')
for key in sorted(classdict):
classdict[key.encode()] = value = classdict.pop(key)
classdict[key] = cls.wrap('{}.{}'.format(name, key), value)
return super().__new__(cls, name, bases, classdict)
def wrap(key, value):
sign('VerboseMetaclass')
## if isinstance(value, types.FunctionType):
## return VerboseFunction(key, value)
return value
class VerboseFunction:
def __init__(self, name, func):
vars(self).update(locals())
def __call__(self, *args, **kwargs):
if self.name.endswith('.__init__'):
print('SPECIAL !!!')
name = self.call(args, kwargs)
print('[ -> ] {!s}\n'.format(name))
try:
value = self.func(*args, **kwargs)
print('[ <- ] {!s} [return {!r}]\n'.format(name, value))
return value
except:
value = sys.exc_info()[1]
print('[ <- ] {!s} [raise {!r}]\n'.format(name, value))
raise
def call(self, args, kwargs):
args = tuple('{!r}'.format(item) for item in args)
kwargs = tuple('{!s}={!r}'.format(key, kwargs[key])
for key in sorted(kwargs))
return '{}({})'.format(self.name, ', '.join(args + kwargs))
class Metaclass(type, metaclass=VerboseMetaclass):
@classmethod
def __prepare__(metacls, name, bases):
sign('Metaclass')
return super().__prepare__(name, bases)
def __new__(cls, name, bases, classdict):
sign('Metaclass')
for key, value in {'__new__': cls.new, '__init__': cls.init}.items():
if key in classdict:
classdict[key.encode()] = classdict[key]
classdict[key] = value
return super().__new__(cls, name, bases, classdict)
def __init__(self, name, bases, classdict):
sign('Metaclass')
return super().__init__(name, bases, classdict)
def __call__(self):
sign('Metaclass')
return super().__call__()
def new(cls):
sign('Metaclass')
return vars(cls)[b'__new__'](cls)
def init(self):
sign('Metaclass')
return vars(self.__class__)[b'__init__'](self)
class Test(metaclass=Metaclass):
def __new__(cls):
sign('Test')
return super().__new__(cls)
def __init__(self):
sign('Test')
return super().__init__()
def run(self):
sign('Test')
Test().run()