定义一个简单的方法:
class Foo:
def bar(self):
print('bar!')
现在使用
inspect.ismethod
:
>>> from inspect import ismethod
>>> ismethod(Foo.bar)
False
这是为什么呢?
bar
不是方法吗?
查阅文档:
inspect.ismethod(object)
如果对象是用 Python 编写的绑定方法,则返回
。True
所以
ismethod
实际上只是测试 bound 方法。这意味着如果您创建一个实例并通过该实例访问该方法,ismethod
将返回True
:
>>> obj = Foo()
>>> ismethod(obj.bar)
True
“绑定”方法意味着已经绑定到对象的方法,因此该对象作为
self
参数提供。这就是您如何在不带参数的情况下调用 obj.bar()
,即使 bar
被声明为具有一个参数。
我们还可以通过查看类型来看出区别:
>>> Foo.bar
<function Foo.bar at 0x7853771f1ab0>
>>> obj.bar
<bound method Foo.bar of <__main__.Foo object at 0x7853771e4850>>
只有后者才是绑定方法。
Foo.bar
是一个函数,Python的类型系统不认为它是一个方法。
那么为什么
inspect.ismethod
会有这样的行为呢?
从Python的角度来看,
bar
是一个普通函数,恰好被类Foo
的属性引用。为了清楚地说明这一点,假设您在类外部定义了一个函数,然后将其分配给类属性:
def baz(self):
print('baz!')
Foo.baz = baz
如果你调用
ismethod(baz)
,你应该期望它是 False
,因为 baz
显然只是在外部作用域中声明的函数。如果调用 ismethod(Foo.baz)
,你会得到相同的结果,因为 Foo.baz
只是对同一函数的引用。事实上,表达式 Foo.baz
被求值以获取对函数 before 的引用,该引用作为参数传递给 ismethod
;当然,ismethod
不能根据该论点的来源对同一论点给出不同的答案。
当函数
bar
在类Foo
内声明时,同样适用。类在 Python 中的工作方式几乎相当于在类外部声明函数,然后将其分配给与函数同名的类属性。所以 bar
和 baz
的工作方式完全相同:
>>> obj.baz
<bound method baz of <__main__.Foo object at 0x7853771e4850>>
>>> obj.baz()
baz!
简而言之,
Foo.bar
“不是方法”,因为在 Python 中,“方法”在绑定到实例之前只是普通函数。