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

Posted

技术标签:

【中文标题】Python:inspect.ismethod 是如何工作的?【英文标题】:Python: how does inspect.ismethod work? 【发布时间】:2011-03-14 19:24:36 【问题描述】:

我正在尝试获取班级中所有方法的名称。 在测试检查模块的工作方式时,我通过obj = MyClass.__dict__['mymethodname'] 提取了我的一种方法。

但是现在inspect.ismethod(obj) 返回Falseinspect.isfunction(obj) 返回True,我不明白为什么。是否有一些奇怪的方法将方法标记为我不知道的方法?我以为只是它在类中定义并以self作为它的第一个参数。

【问题讨论】:

【参考方案1】:

您正在看到 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")

【讨论】:

【参考方案2】:

使用the source

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

【讨论】:

【参考方案3】:

嗯,你的意思是obj.mymethod 是一个方法(隐式传递self)而Klass.__dict__['mymethod'] 是一个函数?

基本上Klass.__dict__['mymethod'] 是“原始”函数,可以通过称为描述符 的东西转换为方法。这意味着类中的每个函数既可以是普通函数,也可以是方法,这取决于您访问它们的方式。这就是类系统在 Python 中的工作方式,非常正常。

如果你想要方法,你不能通过__dict__(无论如何你都不应该这样做)。要获取所有方法,您应该执行inspect.getmembers(Klass_or_Instance, inspect.ismethod)

您可以阅读details here,有关此的说明在“用户定义的方法”下。

【讨论】:

当我创建一个继承自内置 python 类的类时,有没有办法只获取用户定义的方法?查看__dict__ 似乎可行,但您说不应该这样做。还有其他方法吗? @Eskil - 查看__dict__ 不适用于没有__dict__ 的类(“新式类”默认情况下没有它),或者将无法正常工作具有它但未在__dict__ 中反映其属性的类(可能是由扩展定义的类和一些内置类的情况)。使用inspect.getmembers,如上图。 但是 inspect.getmembers(Klass_or_Instance, inspect.ismethod) ,如上所述,提供所有方法,而不仅仅是用户定义的方法。查看 method.__module__ 是否与我自己的模块匹配是否安全? 它查看一个对象并为您提供所有作为方法的成员(duh)。你究竟想要什么?只有在给定类上定义的成员?【参考方案4】:

从对@THC4k 答案的评论来看,OP 似乎想要区分内置方法和纯 Python 代码中定义的方法。用户定义的方法属于types.MethodType,但内置的方法不是。

你可以像这样得到各种类型:

import inspect
import types

is_user_defined_method = inspect.ismethod

def is_builtin_method(arg):
    return isinstance(arg, (type(str.find), type('foo'.find)))

def is_user_or_builtin_method(arg):
    MethodType = types.MethodType
    return isinstance(arg, (type(str.find), type('foo'.find), MethodType))

class MyDict(dict):
    def puddle(self): pass

for obj in (MyDict, MyDict()):
    for test_func in (is_user_defined_method, is_builtin_method,
            is_user_or_builtin_method):
        print [attr 
            for attr in dir(obj)
            if test_func(getattr(obj, attr)) and attr.startswith('p')]

哪个打印:

['puddle']
['pop', 'popitem']
['pop', 'popitem', 'puddle']
['puddle']
['pop', 'popitem']
['pop', 'popitem', 'puddle']

【讨论】:

啊,是的,如果我让类继承自“纯”python 类,这就是我所需要的。但是假设我想创建一个 unittest.TestCase 的子类,并且想区分我自己的新方法和 TestCase 方法?这在这种情况下不起作用,因为这两种类型都从 inspect.ismethod 返回 True。【参考方案5】:

您可以使用 dir 来获取可用方法/属性/等的名称,然后遍历它们以查看哪些是方法。像这样:

[ mthd for mthd in dir(FooClass) if inspect.ismethod(myFooInstance.__getattribute__(mthd)) ]

我期待有一个更清洁的解决方案,但如果没有其他人想出一个,这可能是你可以使用的东西。如果我不必使用类的实例来使用 getattribute,我会很高兴。

【讨论】:

以上是关于Python:inspect.ismethod 是如何工作的?的主要内容,如果未能解决你的问题,请参考以下文章

基础入门_Python-模块和包.运维开发中inspect自省模块的最佳实践?

如何在 Python 中编写有效的类装饰器?

按照代码中的顺序获取类的方法

什么是python?python有什么用途?

什么是Python?Python涉及哪些领域?

什么是Python?Python涉及哪些领域?