Python: inspect.ismethod是如何工作的?

16 投票
5 回答
6698 浏览
提问于 2025-04-16 01:10

我想获取我类中所有方法的名字。在测试 inspect 模块的工作原理时,我通过 obj = MyClass.__dict__['mymethodname'] 提取了我的一个方法。

但是现在 inspect.ismethod(obj) 返回 False,而 inspect.isfunction(obj) 返回 True,我不明白这是为什么。难道有一些我不知道的奇怪方式来标记方法吗?我以为只要在类中定义,并且第一个参数是 self 就可以了。

5 个回答

1

你是说 obj.mymethod 是一个方法(自动传入 self),而 Klass.__dict__['mymethod'] 是一个普通函数吗?

其实 Klass.__dict__['mymethod'] 是一个“原始”的函数,通过一种叫做 描述符 的东西可以把它变成方法。这意味着,类中的每个函数 都可以是普通函数,也可以是方法,这取决于你怎么去访问它们。这就是 Python 中类系统的工作方式,非常正常。

如果你想要方法,就不能通过 __dict__ 来获取(其实你本来就不应该这样做)。要获取所有方法,你应该使用 inspect.getmembers(Klass_or_Instance, inspect.ismethod)

你可以在这里阅读更多细节:详细信息,关于这个的解释在“用户定义的方法”部分。

4

使用这个链接

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') 
12

你看到的是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")

撰写回答