python-2.7 - 使用元类包装所有类方法

标签 python-2.7 inheritance metaprogramming wrapper

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

我的类继承自python dict类,我想包装这个父类的所有方法,例如__setitem__, __getitem__

在我尝试实现这一目标的过程中,我编写了一个元类,它使用元类中的 __init__ 方法将所有方法包装在其子类中,所以我可以访问子类的对象(而不是不包含父方法的类定义)。

但是,运行代码后,我发现包装方法从未被调用。意味着包裹没有成功。

您能帮忙找出问题所在吗?

我的代码:

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__()打印的引用...

最佳答案

当元类__init__被调用时,class对象已经被构建,因此修改属性字典(代码中的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)

关于python-2.7 - 使用元类包装所有类方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51649227/

相关文章:

python - 使用 virtualenv 安装 django1.7 和 Python 3.4

java - 扩展 Log4JLogger 并在运行时调用子类

c++ - 通用实现获取类型列表的大小

c - 知道 void * 分配类型的宏

许多参数的python线程应用程序错误

python - 在python中的同一进程中执行bash命令

c++ - 重写私有(private)函数,它与 protected 函数有何不同?

c++ - 通过 SFINAE GCC 错误测试 std::ostream operator<< 是否存在?

Python以交替方式组合两个不等长的列表

javascript - 数据与 Javascript 中的继承冲突