首页 > 解决方案 > Python中调用方法的不同方式,它们是如何工作的?

问题描述

class Test():
    def a(self):
        return 6
Test_instance=Test()
print(Test.a(Test_instance))
print(Test_instance.a())
print(Test.a(Test_instance,3))
print(Test_instance.a(3))

上面的代码给了我以下结果:

6
6
TypeError: a() takes 1 positional argument but 2 were given

如果我排除该行print(Test.a(Test_instance,3)),我会得到相同的打印输出。但是,不是类和对象a的方法吗?当我写作时,我假设我给 of 的方法一个参数,而当我写作时,我假设我给of 的方法两个参数。但是错误说这给出了 2 个参数。不应该是3吗?TestTest_instanceTest_instance.a()a()Test_instanceTest.a(Test_instance)a()TestTest.a(Test_instance,3)

标签: pythonclassobject

解决方案


但是“a”不是Test对象和Test_instance对象的方法吗?

这的确是。

当我写作时,我假设我给Test_instance的“a”方法Test_instance.a()一个参数,而当我写作时,我假设我给Test的“a”方法两个参数。Test.a(Test_instance)

正确的。但这仅适用于实例上的方法调用。

但是错误说这Test.a(Test_instance,3)给出了 2 个参数。不应该是3吗?

不,它是 2,因为您直接在类上调用该方法,而不是通过实例。

直接在类上调用方法会按原样调用它。

但是,在实例上调用方法会将实例作为第一个参数添加。

造成这种情况的原因是内部因素。

如果我这样做instance.XX是一个类成员并实现__get__()方法(描述符协议),在内部X.__get__()被调用并为instance.X.

并且函数实现描述符协议以创建实例方法对象,该对象负责将实例作为第一个参数。

所以,在你的例子中,你也可以这样做

>>> print(Test_instance.a)
<bound method Test.a of <__main__.Test instance at 0x7f6e232e3690>>
>>> Test.a.__get__(Test_instance, Test)
<bound method Test.a of <__main__.Test instance at 0x7f6e232e3690>>

这两种“绑定方法”都是我所说的“实例方法对象”。

其他示例:

class Desc(object):
    def __get__(self, a, b):
        print('Calling __get__(%r, %r, %r)' % (self, a, b))
        return a or b
class Test():
    x = Desc()

>>> Test.x
Calling __get__(<__main__.Desc object at 0x7f6e232e1810>, None, <class __main__.Test at 0x7f6e232ea050>)
<class __main__.Test at 0x7f6e232ea050>
>>> inst = Test()
>>> inst.x
Calling __get__(<__main__.Desc object at 0x7f6e232e1810>, <__main__.Test instance at 0x7f6e232e3c80>, <class __main__.Test at 0x7f6e232ea050>)
<__main__.Test instance at 0x7f6e232e3c80>

这里会发生什么?

Test.x接受x成员Test并调用其.__get__(x, None, Test). 此方法返回b(设置为Test),因为a参数是None

inst.x接受x成员Test并调用其.__get__(x, inst, Test). 这反过来又回来了a

以类似的方式,方法被设置为工作。

属性也使用相同的机制,顺便说一句。

如果您使用@classmethodand装饰器,它们会将函数包装到一些行为@staticmethod略有不同的包装对象中。.__get__()


推荐阅读