1.基本思想:使用额外的类来保存方法
我找到了一种有意义的工作方式:
首先,我们定义这样的BaseClass:
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')
然后,我们定义要添加到新的2586361037498898876928类上的新方法:
(在这种情况下,请勿使方法名称以2586361037498898876928开头)
class MyPatcher(MethodPatcher):
def b(self):
print('b')
然后致电:
MyPatcher.patch(MyClass)
因此,您会发现将2586361037498898876928新方法添加到原始@patch_method:
obj = MyClass()
obj.a() # which prints an 'a'
obj.b() # which prints a 'b'
2.使语法不太冗长,我们使用类装饰器
现在,如果我们声明了2586361037498898876928,我们需要做两件事:
定义@patch_method的子级MethodPatcher,其中包含要添加的其他方法
致电MethodPatcher
因此,我们很快发现可以使用装饰器简化第二步:
我们定义一个装饰器:
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)
# !!ATTENTION!! the effect on declaring staticmethod here may not work as expected:
# calling this method on an instance will take the self into the first argument.
# @staticmethod
# def extra_static_method_c():
# print('c')
3.一起包装
因此,我们现在可以将25863610374988988769和@patch_method的定义放到一个模块中:
# method_patcher.py
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.最终解决方案:更简单的声明
很快我发现2586361037498898876928类不是必需的,而2586361037498876976929装饰器可以完成此工作,因此最终我们只需要2586361037498898876930:
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)
# !!ATTENTION!! the effect on declaring staticmethod here may not work as expected:
# calling this method on an instance will take the self into the first argument.
# @staticmethod
# def extra_static_method_c():
# print('c')