Python: inspect.ismethod是如何工作的?
我想获取我类中所有方法的名字。在测试 inspect 模块的工作原理时,我通过 obj = MyClass.__dict__['mymethodname']
提取了我的一个方法。
但是现在 inspect.ismethod(obj)
返回 False
,而 inspect.isfunction(obj)
返回 True
,我不明白这是为什么。难道有一些我不知道的奇怪方式来标记方法吗?我以为只要在类中定义,并且第一个参数是 self
就可以了。
5 个回答
你是说 obj.mymethod
是一个方法(自动传入 self
),而 Klass.__dict__['mymethod']
是一个普通函数吗?
其实 Klass.__dict__['mymethod']
是一个“原始”的函数,通过一种叫做 描述符 的东西可以把它变成方法。这意味着,类中的每个函数 都可以是普通函数,也可以是方法,这取决于你怎么去访问它们。这就是 Python 中类系统的工作方式,非常正常。
如果你想要方法,就不能通过 __dict__
来获取(其实你本来就不应该这样做)。要获取所有方法,你应该使用 inspect.getmembers(Klass_or_Instance, inspect.ismethod)
。
你可以在这里阅读更多细节:详细信息,关于这个的解释在“用户定义的方法”部分。
使用这个链接
def ismethod(object):
"""Return true if the object is an instance method.
Instance method objects provide these attributes:
__doc__ documentation string
__name__ name with which this method was defined
__func__ function object containing implementation of method
__self__ instance to which this method is bound"""
return isinstance(object, types.MethodType)
第一个参数叫self
是个约定俗成的规则。通过从类的字典中按名字访问这个方法,你实际上是绕过了绑定,所以它看起来像是一个普通的函数,而不是一个方法。
如果你想通过名字来访问这个方法,可以使用
getattr(MyClass, 'mymethodname')
你看到的是Python背后的一些工作原理。
当你写 f = MyClass.__dict__['mymethodname']
时,你得到的是“mymethodname”的原始实现,这其实就是一个普通的函数。要调用它,你需要额外传入一个参数,也就是类的实例。
当你写 f = MyClass.mymethodname
(注意这里没有在mymethodname后面加括号),你得到的是MyClass类的一个未绑定方法,这个方法是一个MethodType
的实例,它把你之前得到的原始函数包裹起来。调用它时,你同样需要传入一个类的实例。
当你写 f = MyClass().mymethodname
(注意我在调用方法之前先创建了MyClass的一个对象),你得到的是MyClass类实例的一个绑定方法。你不需要再传入额外的类实例,因为它已经存储在这个方法里面了。
如果你想通过字符串形式的方法名来获取这个被包裹的方法(无论是绑定的还是未绑定的),可以使用 getattr
,正如gnibbler提到的那样。例如:
unbound_mth = getattr(MyClass, "mymethodname")
或者
bound_mth = getattr(an_instance_of_MyClass, "mymethodname")