今天有同学在公众号粉丝群问了这样一个问题:
他的问题,简单来说,就是想动态替换一个对象的实例方法,简化代码如下:
class Test: def __init__(self, name): self.name = name def work(self, job): print(f'{self.name}正在{job}') def work(self, job1, job2): print(f'{self.name}正在同时做两个工作,分别是{job1}和{job2}') t = Test('kingname') t.work = work
当我们在替换之前,直接运行t.work('job')
,效果如下:
这个同学期望在替换以后,运行t.work('job1', 'job2')
,能够输出:kingname正在同时做两个工作,分别是job1和job2
。但上面的代码,直接运行以后会报错,如下图所示:
这说明,替换以后,在调用t.work
的时候,Python 不会自动把self
传入到第一个参数。
在以前的文章里面,我们已经讲过,实例方法的第一个参数self
,就是这个实例对象自身。我们可以写一段代码来验证这一点:
class Test: def __init__(self, name): self.name = name def work(self, job): print(f'{self.name}正在{job}') def check(self, instance): print(f'self的内存地址是:{id(self)}') print(f'instance 的内存地址是:{id(instance)}') print('self与 instance 就是同一个对象:', self is instance) t = Test('kingname') t.check(t)
运行效果如下图所示:
知道这一点以后,要解决动态替换以后报错的问题,最简单的方法就是手动把实例对象作为第一个参数传入进去,如下图所示:
但这样做显然很麻烦,每次都要手动传入第一个实例对象。有没有什么办法能省略它呢?这个时候,如果你记得我公众号里面的这篇文章偏函数:在Python中设定默认参数的另一种办法,那么你就有办法了。使用偏函数,提前把第一个参数固定下来,就能解决问题:
from functools import partial def work(self, job1, job2): print(f'{self.name}正在同时做两个工作,分别是{job1}和{job2}') simple_work = partial(work, t) t.work = simple_work
运行效果如下图所示: