Python 更改方法定义

Python 更改方法定义,python,inheritance,Python,Inheritance,我想更改类的方法定义。 这就是我的情况: (我正在从其他文件导入这些类) 当我尝试执行它时,我得到: my_method_a() takes exactly 1 argument (0 given) 因为它没有“自我” 请提供帮助。如果在修补方法之前运行类型(b.a.method\u a),您将看到。在补丁后运行相同的代码会产生。为了使函数作为方法正常工作,它必须是类的属性,而不是类的实例。当您手动调用从函数生成方法的魔法时,以下操作将起作用: b.a.method_a = my_method

我想更改类的方法定义。 这就是我的情况:

(我正在从其他文件导入这些类)

当我尝试执行它时,我得到:

my_method_a() takes exactly 1 argument (0 given)
因为它没有“自我”


请提供帮助。

如果在修补方法之前运行
类型(b.a.method\u a)
,您将看到
。在补丁后运行相同的代码会产生
。为了使函数作为方法正常工作,它必须是类的属性,而不是类的实例。当您手动调用从函数生成方法的魔法时,以下操作将起作用:

b.a.method_a = my_method_a.__get__(b.a, A)
有关更多信息,请参阅


不同之处在于,在补丁之后调用
b.a.method\u a()
时,
method\u a
是实例
b.a
的属性,而不是类
a
的属性。因此,永远不会调用函数的
\uuuu get\uuu
方法来生成已将
b.a
绑定到
方法a
的第一个参数的
instancemethod
对象


从一个角度来看,
b.a.方法a()
a.a.方法a(b.a)
相同。Python是如何进行这种转换的?您需要了解描述符协议。所有函数对象都实现了
\uuu get\uu
方法来返回
instancemethod
对象,您可以将其视为原始函数,第一个参数绑定到相应的对象。考虑这个代码:

b = B()
b.a.method_a()
  • b
    是否具有名为
    a
    的属性?对我们在
    B.\uuuuu init\uuuu
    中设置它
  • b.a
    是否有属性
    method\u a
    ?没有
  • 类型(b.a)
    (即
    a
    )是否具有属性
    方法\u a
    ?对
  • 调用
    A.method\u A.\uuuu get\uu(b.A,A)
    ,因为
    method\u A
    是为实例而查找的。结果是一个实例方法对象,其第一个参数绑定到
    b.a
    。(这就是为什么您可以考虑<代码> B.A.MaultAd())<代码>与<代码> A.方法A(B.A) >
  • 使用零参数调用结果实例方法
  • 现在考虑这个代码。

    b = B()
    b.a.method_a = my_method_a
    b.a.method_a()
    
  • b
    是否具有名为
    a
    的属性?对我们在
    B.\uuuuu init\uuuu
    中设置它

  • b.a
    是否有属性
    method\u a
    。我们在打电话之前就把它调好了

  • 由于
    b.a.method\u a
    是实例查找,而不是类查找,因此不会调用描述符协议,也不会调用
    b.a.method\u a.\u____
    ,即使
    my_method\u a
    与其他所有函数一样,也不会调用

  • 使用零参数调用
    b.a.method\u a

    这会产生错误,因为函数需要一个参数


  • 为什么不使用继承和方法重写:

    from module import A, B
    
    class myA(A):
        def method_a(self):
            print self.str + ' other definition'
    
    class myB(B):
        def __init__(self, str):
            self.a = myA(str)
    
    def main():
        b = myB('hello')
        b.method_b()
    
    if __name__ == '__main__':
        main()
    

    为什么这被认为是可以接受的-我希望适当的继承和方法重写会更好,并且更易于理解和维护。通过修补
    b.a
    ,您已经破坏了继承
    b.a
    的行为不再与类型
    a
    的其他实例相同。我的意思是同时上这两门课。对不起,gkusner,我把你误认为OP,误解了你的问题。我主要是通过Python内部的方法查找工作原理来说明为什么这种天真的尝试不起作用,以及需要做些什么才能使它起作用。在某些情况下,这种定向修补是有用的;模拟对象进行测试就是一种情况。(例如,
    mock
    包为您隐藏了这些细节。)我明白您的意思,并且原则上同意您的意见-但是从可维护性的角度来看,这种类型的补丁似乎是错误的-但是它非常酷-我从未真正看到过它。
    from module import A, B
    
    class myA(A):
        def method_a(self):
            print self.str + ' other definition'
    
    class myB(B):
        def __init__(self, str):
            self.a = myA(str)
    
    def main():
        b = myB('hello')
        b.method_b()
    
    if __name__ == '__main__':
        main()