替换一个实例方法,没你想的那么简单

发表于:2021-4-01 09:24

字体: | 上一篇 | 下一篇 | 我要投稿

 作者:写代码的明哥    来源:Python编程时光

#
Python
分享:
  思路一:简单地替换
  当你想对类实例的方法进行替换时,你可能想到的是直接对他进行粗暴地替换:
  class People: 
      def speak(self): 
          print("hello, world") 
   
   
  def speak(self): 
      print("hello, python") 
   
  p = People() 
  p.speak = speak 
  p.speak() 
  但当你试着执行这段代码的时候,就会发现行不通,它提示我们要传入 self 参数:
  Traceback (most recent call last): 
    File "/Users/MING/Code/Python/demo.py", line 12, in <module> 
      p.speak() 
  TypeError: speak() missing 1 required positional argument: 'self' 
  不对啊~ self 不是实例本身吗?函数不是一直就这么写的?
  实际上你这么替换,speak 就变成了一个 function,而不是一个和实例绑定的 method ,你可以把替换前后的 speak 打印出来
  p = People() 
  print(p.speak) 
  p.speak = speak 
  print(p.speak) 
  输出结果如下,区别非常明显
  <bound method People.speak of <__main__.People object at 0x10cfa7fd0>> 
  <function speak at 0x10ca10040> 
  这种方法,只能用在替换不与实例绑定的静态方法上,不然你每次调用的时候,就得手动传入实例本身,但这样调用就会变得非常怪异。
  思路二:利用 im_func
  有 Python 2 使用经验的朋友,可以会知道类实例的方法,都有 im_func 和 im_class 属性,分别指向了该方法的函数和类。
  很抱歉的是,这些在 Python3 中全都取消了,意味你无法再使用 im_func 和 im_class 。
  但即使你身处 Python 2 的环境下,你想通过 im_func 去直接替换函数,也仍然是有问题的。
  因为在 Python2 中不推荐普通用户对类实例的方法进行替换,所以 Python 给类实例的方法赋予了只读属性。
  思路三:非常危险的字节码替换
  表层不行,但这个方法在字节码层面却是可行的。
  这种方法,非常的粗暴且危险,他会直接影响到使用 People 的所有实例的 speak 方法,因此这种方法千万不要使用。
  思路四:利用 types 绑定方法
  在 types 中有一个 MethodType,可以将普通方法与实例进行绑定。
  绑定后,就可以直接替换掉原实例的 speak 方法了,完整代码如下:
  import types 
   
  class People: 
      def speak(self): 
          print("hello, world") 
   
   
  def speak(self): 
      print("hello, python") 
   
  p = People() 
  p.speak = types.MethodType(speak, p) 
  p.speak() 
  这种方法,最为安全,不会影响其他实例。并且 Python 2 和 Python 3 都适用,是官方推荐的一种做法。
  总结一下
  · 直接替换:只适用于静态方法
  · 使用 im_func 替换:行不通
  · 使用 im_func.func_code 替换字节码:非常危险,请不要使用
  · 使用 types.MethodType 进行方法绑定:安全且有效,推荐使用

      本文内容不用于商业目的,如涉及知识产权问题,请权利人联系51Testing小编(021-64471599-8017),我们将立即处理
《2023软件测试行业现状调查报告》独家发布~

关注51Testing

联系我们

快捷面板 站点地图 联系我们 广告服务 关于我们 站长统计 发展历程

法律顾问:上海兰迪律师事务所 项棋律师
版权所有 上海博为峰软件技术股份有限公司 Copyright©51testing.com 2003-2024
投诉及意见反馈:webmaster@51testing.com; 业务联系:service@51testing.com 021-64471599-8017

沪ICP备05003035号

沪公网安备 31010102002173号