3

下面的代码可以让我跟随元类如何工作的操作。但是,当第 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()
4

2 回答 2

2

VerboseMetaclass可以修改类,也VerboseFunction可以删除类。VerboseMetaclass.wrap应作如下修改,并wrap_function应加以补充。

@classmethod
def wrap(cls, key, value):
    sign('VerboseMetaclass')
    if isinstance(value, types.FunctionType):
        return cls.wrap_function(key, value)
    return value

def wrap_function(name, func):
    sign('VerboseMetaclass')
    @functools.wraps(func)
    def verbose_function(*args, **kwargs):
        args_str = tuple(repr(item) for item in args)
        kwargs_str = tuple('{!s}={!r}'.format(*pair)
                           for pair in sorted(kwargs.items()))
        signature = '{}({})'.format(name, ', '.join(args_str + kwargs_str))
        print('[ -> ] {}\n'.format(signature))
        try:
            value = func(*args, **kwargs)
            print('[ <- ] {!s} [return {!r}]\n'.format(signature, value))
            return value
        except:
            value = sys.exc_info()[1]
            print('[ <- ] {!s} [raise {!r}]\n'.format(signature, value))
            raise
    return verbose_function

编辑:此代码的完成的第二稿可以在下面看到。此示例的目的是观察创建、实例化和监视类及其实例所涉及的“机器”。大部分代码也是自我监控的(除了VerboseMetaclass),因此可以看到代码本身是如何运行的。通过将类的元类设置为Metaclass,您自己的类及其实例也将打印出监控消息。该Test课程提供了一个示例。

import types, functools, sys

class VerboseMetaclass(type):

    def __new__(cls, name, bases, classdict):
        for key in sorted(filter(
            lambda name: isinstance(name, str), classdict)):
            classdict[key] = cls.wrap('{}.{}'.format(name, key), classdict[key])
        return super().__new__(cls, name, bases, classdict)

    @classmethod
    def wrap(cls, name, value):
        if isinstance(value, types.FunctionType):
            return cls.wrap_function(name, value)
        if isinstance(value, classmethod):
            return classmethod(cls.wrap_function(name, value.__func__))
        if isinstance(value, staticmethod):
            return staticmethod(cls.wrap_function(name, value.__func__))
        try:
            return VerboseData(name, value)
        except NameError:
            return value

    def wrap_function(name, func):
        @functools.wraps(func)
        def verbose_function(*args, **kwargs):
            args_str = tuple((object.__repr__(item)
                              if isinstance(item, VerboseData)
                              else repr(item)) for item in args)
            kwargs_str = tuple('{!s}={!r}'.format(*pair)
                               for pair in sorted(kwargs.items()))
            signature = '{}({})'.format(name, ', '.join(args_str + kwargs_str))
            print('[ -> ] {}\n'.format(signature))
            try:
                value = func(*args, **kwargs)
                print('[ <- ] {!s} [return {!r}]\n'.format(signature, value))
                return value
            except:
                value = sys.exc_info()[1]
                print('[ <- ] {!s} [raise {!r}]\n'.format(signature, value))
                raise
        return verbose_function

class VerboseData(metaclass=VerboseMetaclass):

    def __init__(self, name, value):
        vars(self).update(locals())

    def __repr__(self):
        return repr(self.value)

    def __get__(self, instance, owner):
        value = self.value
        if isinstance(value, (property, VerboseData)):
            value = value.__get__(instance, owner)
        print('[ get ] {!s} = {!r}\n'.format(self.name, value))
        return value

    def __set__(self, instance, value):
        print('[ set ] {!s} = {!r}\n'.format(self.name, value))
        if isinstance(self.value, (property, VerboseData)):
            self.value.__set__(instance, value)
        else:
            self.value = value

    def __delete__(self, instance):
        print('[ XX ] {}\n'.format(self.name))
        if isinstance(self.value, (property, VerboseData)):
            self.value.__delete__(instance)
        else:
            del self.value

    def __iter__(self):
        return iter(self.value)

class Metaclass(VerboseMetaclass, metaclass=VerboseMetaclass):

    @classmethod
    def __prepare__(metacls, name, bases):
        return super().__prepare__(name, bases)

    def __new__(cls, name, bases, classdict):
        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):
        return super().__init__(name, bases, classdict)

    def __call__(self, *args, **kwargs):
        return super().__call__(*args, **kwargs)

    def new(cls, *args, **kwargs):
        for base in cls.__mro__:
            try:
                return vars(base)[b'__new__'](cls, *args, **kwargs)
            except KeyError:
                pass
        return object.__new__(cls, *args, **kwargs)

    def init(self, *args, **kwargs):
        for base in self.__class__.__mro__:
            try:
                return vars(base)[b'__init__'](self, *args, **kwargs)
            except KeyError:
                pass
        return object.__init__(self)

if __name__ == '__main__':
    class Test(metaclass=Metaclass):

        def __new__(cls):
            return super().__new__(cls)

        def __init__(self):
            return super().__init__()

        def run(self):
            pass

    Test().run()
于 2012-05-25T13:19:20.850 回答
0

您只是迷失在自己设计的迷宫中,无论是那个人还是我 :)

您的错误可以建模为:

class VerboseFunction:

    def __init__(self, name, func):
        self.name, self.func = name, func

    def __call__(self, *args, **kwargs):
        return self.func(*args, **kwargs)

class Metaclass:

    def __init__(self):
        pass

    # Comment out the line below
    __init__ = VerboseFunction('Metaclass.__init__', __init__)

print(Metaclass())

这意味着您Metaclass.__init__()直接调用而没有 self 实例。

于 2012-05-25T00:13:21.277 回答