1. 基本思路:使用额外的类来保存方法
我发现了一种有意义的方法来完成这项工作:
首先,我们定义一个这样的基类:
class MethodPatcher:
@classmethod
def patch(cls, target):
for k in cls.__dict__:
obj = getattr(cls, k)
if not k.startswith('_') and callable(obj):
setattr(target, k, obj)
现在我们有了一个原始类:
class MyClass(object):
def a(self):
print('a')
接下来,我们定义想要添加到新的Patcher
类中的新方法:
(在这种情况下,请勿以_
开头命名方法)
class MyPatcher(MethodPatcher):
def b(self):
print('b')
然后调用:
MyPatcher.patch(MyClass)
因此,在原始的 MyClass
中添加了新方法 b(self)
:
obj = MyClass()
obj.a()
obj.b()
2. 使语法更简洁,我们使用类装饰器
现在如果我们已经声明了MethodPatcher
,我们需要做两件事:
- 定义一个
ModelPatcher
的子类ChildClass
,其中包含要添加的额外方法
- 调用
ChildClass.patch(TargetClass)
因此,我们很快发现第二步可以通过使用装饰器来简化:
我们定义一个装饰器:
def patch_methods(model_class):
def do_patch(cls):
cls.patch(model_class)
return do_patch
我们可以这样使用它:
@patch_methods(MyClass)
class MyClassPatcher(MethodPatcher):
def extra_method_a(self):
print('a', self)
@classmethod
def extra_class_method_b(cls):
print('c', cls)
3. 组合起来
现在,我们可以将MethodPatcher
和patch_method
的定义放入一个单独的模块中:
class MethodPatcher:
@classmethod
def patch(cls, target):
for k in cls.__dict__:
obj = getattr(cls, k)
if not k.startswith('_') and callable(obj):
setattr(target, k, obj)
def patch_methods(model_class):
def do_patch(cls):
cls.patch(model_class)
return do_patch
因此,我们可以自由地使用它:
from method_patcher import ModelPatcher, patch_model
4. 最终方案:更简单的声明
很快我发现MethodPatcher
类并不必要,而@patch_method
装饰器可以完成工作,所以最终我们只需要一个patch_method
:
def patch_methods(model_class):
def do_patch(cls):
for k in cls.__dict__:
obj = getattr(cls, k)
if not k.startswith('_') and callable(obj):
setattr(model_class, k, obj)
return do_patch
使用方法如下:
@patch_methods(MyClass)
class MyClassPatcher:
def extra_method_a(self):
print('a', self)
@classmethod
def extra_class_method_b(cls):
print('c', cls)
__init __()
,所以它没有被执行也就不足为奇了。此外,你必须将新方法添加到类上,而不是实例上。 - Sven Marnacha.func = staticmethod(a._func)
这样的代码。 - Sven Marnach