我试图将所有方法包装在我用特定包装方法编写的类中。
我的类继承自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/