Python 将元类添加到库类

Python 将元类添加到库类,python,metaprogramming,Python,Metaprogramming,在我正在使用的Python库中,我想包装库中类的公共方法。我正在尝试使用元类来这样做 from functools import wraps from types import FunctionType from six import with_metaclass def wrapper(func): @wraps(func) def wrapped(*args, **kwargs): print("wrapped %s" % func) ret

在我正在使用的Python库中,我想包装库中类的公共方法。我正在尝试使用元类来这样做

from functools import wraps
from types import FunctionType
from six import with_metaclass

def wrapper(func):
    @wraps(func)
    def wrapped(*args, **kwargs):
        print("wrapped %s" % func)
        return func(*args, **kwargs)
    return wrapped

class MetaClass(type):
    def __new__(mcs, classname, bases, class_dict):
        library_class_dict = bases[0].__dict__

        print(library_class_dict)

        for attributeName, attribute in library_class_dict.items():
            if type(attribute) == FunctionType and \
                    not attributeName.startswith('_'):
                print("%s %s" % (attributeName, attribute))
                attribute = wrapper(attribute)

            library_class_dict[attributeName] = attribute

        print(library_class_dict)

        return type.__new__(mcs, classname, bases, class_dict)

# this is the class from the library that I cannot edit
class LibraryClass(object):
    def library_method(self):
        print("library method")

class Session(with_metaclass(MetaClass, LibraryClass)):

    def __init__(self, profile, **kwargs):
        super(Session, self).__init__(**kwargs)
        self.profile = profile
当您将其放入Python文件并运行它时,会出现错误

TypeError: Error when calling the metaclass bases
    'dictproxy' object does not support item assignment
我明白,试图直接分配给
\uuu dict\uuu
是个坏主意。那不是我想做的。我更愿意将元类添加到LibraryClass,但我不确定如何添加


我已经讨论了关于Python元类编程的其他StackOverflow问题,但没有遇到任何试图将元类添加到库类的问题,因为在库类中,您无法获取源代码。

您无法分配给代理。使用
setattr()
设置类的属性:

setattr(bases[0], attributeName, attribute)
然而,你不需要一个元类来做这件事,这在这里是完全过分的。您可以在该基类上执行此操作,并执行一次:

for attributeName, attribute in vars(LibraryClass).items():
    if isinstance(attribute, FunctionType) and not attributeName.startswith('_'):
        setattr(LibraryClass, attributeName, wrapper(attribute))

这只需执行一次,而不是每次创建
LibraryClass的子类时都执行一次,基本上您希望执行此操作:

LibraryClass.library_method = wrapper(LibraryClass.library_method)
对于所有方法,将自动执行

使用您的代码片段:

from functools import wraps
from types import FunctionType

class LibraryClass(object):
    def library_method(self):
        print("library method")

def wrapper(func):
    @wraps(func)
    def wrapped(*args, **kwargs):
        print("wrapped %s" % func)
        return func(*args, **kwargs)
    return wrapped
您可以为所有方法编写一个帮助器函数:

def wrap_all_methods(cls):
    for name, obj in cls.__dict__.items():
        if isinstance(obj, FunctionType) and not name.startswith('_'):
            setattr(cls, name, wrapper(obj))
    return cls
LibraryClass = wrap_all_methods(LibraryClass)
现在,包装所有方法:

def wrap_all_methods(cls):
    for name, obj in cls.__dict__.items():
        if isinstance(obj, FunctionType) and not name.startswith('_'):
            setattr(cls, name, wrapper(obj))
    return cls
LibraryClass = wrap_all_methods(LibraryClass)
测试它是否工作:

class Session(LibraryClass):
    pass

s = Session()

s.library_method()
印刷品:

wrapped <function LibraryClass.library_method at 0x109d67ea0>
library method
wrapped
库方法

方法已包装。

如果我对您尝试执行的操作的理解是正确的,我认为类装饰器将更适合完成此任务,并且不太复杂。你给他们打过一针吗。你到底想达到什么目的。2.什么是完整的错误回溯?是否相关?
library\u class\u dict
是对类
dictproxy
对象的引用,不支持赋值。为什么要尝试从元类更改基类?为什么不在调用它们的
super()
方法的新类中添加重写呢?@Pynchia:好吧,每次创建子类时都尝试更改基类(
LibraryClass
)。。冗余的您只需要修改该基类一次,并且不需要为此使用元类。但是你能更准确地描述一下代码应该放在哪里吗?感谢you@Pynchia:任何你喜欢的地方,但在你需要使用任何包装方法之前,请确保它已运行。对我有用。与使用元类相比,代码要少得多。