使用元类包装所有类方法

时间:2018-08-02 08:41:18

标签: python-2.7 inheritance metaprogramming wrapper

我正在尝试将所有方法包装在用特定包装方法编写的类中。

我的类继承自python dict 类,并且我想包装该父类的所有方法,例如 __ setitem__, __getitem __

为了实现这一目标,我编写了一个元类,该元类使用元类中的 __ init __ 方法将所有方法包装在其子类中,因此我可以访问子类的对象(而不是不包含父方法的类定义)。

但是,在运行代码之后,我看到从未调用wrapper方法。意味着包装没有成功。

您能帮忙弄清楚哪里出了问题吗?

我的代码:

def wrapper(func):
    def wrapped(self, *args, **kwargs):
        print 'wrapper.__call__()'
        res = func(self, *args, **kwargs)
        return res
    return wrapped

class MyMeta(type):   
    def __init__(cls, classname, bases, class_dict):
        print 'meta.__init__()'
        new_class_dict = {}
        for attr_name in dir(cls):
            attr = getattr(cls, attr_name)
            if hasattr(attr, '__call__'):
                attr = wrapper(attr)
            new_class_dict[attr_name] = attr
        return super(MyMeta, cls).__init__(classname, bases, new_class_dict)

class MyDict(dict):

    __metaclass__ = MyMeta

    def __init__(self, *args):
        print 'child.__init__()'
        super(MyDict, self).__init__(*args)     

d = MyDict({'key': 'value'})
d['new_key'] = 'new_value'

我得到的打印输出是:

meta.__init__()
child.__init__()

我没有引用 wrapper .__ call __()印刷品,而是将其放置在包装好的方法中...

1 个答案:

答案 0 :(得分:1)

调用元类__init__时,已经建立了class对象,因此在此阶段修改属性dict(代码中的class_dict)确实是完全没有用的。您想改用setattr

class MyMeta(type):   
    def __init__(cls, classname, bases, class_dict):
        for attr_name in dir(cls):
            if attr_name == "__class__":
                # the metaclass is a callable attribute too, 
                # but we want to leave this one alone
                continue
            attr = getattr(cls, attr_name)
            if hasattr(attr, '__call__'):
                attr = wrapper(attr)
                setattr(cls, attr_name, attr)

        # not need for the `return` here
        super(MyMeta, cls).__init__(classname, bases, class_dict)