将元类添加到库 class
Add a MetaClass to a library class
在我使用的 Python 库中,我想包装库中 class 的 public 方法。我正在尝试使用元类来这样做。
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
我知道尝试直接分配给 __dict__
是个坏主意。那不是我想做的。我更愿意将 MetaClass 添加到 LibraryClass,但我不确定如何添加。
我已经解决了有关 Python MetaClass 编程的其他 Whosebug 问题,但还没有遇到任何试图将 MetaClass 添加到库 class 的问题,而您无法获得源代码代码。
您不能分配给 dictproxy。使用 setattr()
在 class:
上设置属性
setattr(bases[0], attributeName, attribute)
但是,您不需要元class 来执行此操作,这在这里完全是矫枉过正。您可以 在那个基础 class 上做一次,然后做一次:
for attributeName, attribute in vars(LibraryClass).items():
if isinstance(attribute, FunctionType) and not attributeName.startswith('_'):
setattr(LibraryClass, attributeName, wrapper(attribute))
这只会执行一次,而不是每次创建 LibraryClass
的子class 时执行。
基本上你想这样做:
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)
测试是否有效:
class Session(LibraryClass):
pass
s = Session()
s.library_method()
打印:
wrapped <function LibraryClass.library_method at 0x109d67ea0>
library method
方法已包装。
在我使用的 Python 库中,我想包装库中 class 的 public 方法。我正在尝试使用元类来这样做。
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
我知道尝试直接分配给 __dict__
是个坏主意。那不是我想做的。我更愿意将 MetaClass 添加到 LibraryClass,但我不确定如何添加。
我已经解决了有关 Python MetaClass 编程的其他 Whosebug 问题,但还没有遇到任何试图将 MetaClass 添加到库 class 的问题,而您无法获得源代码代码。
您不能分配给 dictproxy。使用 setattr()
在 class:
setattr(bases[0], attributeName, attribute)
但是,您不需要元class 来执行此操作,这在这里完全是矫枉过正。您可以 在那个基础 class 上做一次,然后做一次:
for attributeName, attribute in vars(LibraryClass).items():
if isinstance(attribute, FunctionType) and not attributeName.startswith('_'):
setattr(LibraryClass, attributeName, wrapper(attribute))
这只会执行一次,而不是每次创建 LibraryClass
的子class 时执行。
基本上你想这样做:
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)
测试是否有效:
class Session(LibraryClass):
pass
s = Session()
s.library_method()
打印:
wrapped <function LibraryClass.library_method at 0x109d67ea0>
library method
方法已包装。