我想通过类中的方法进行迭代,或者根据目前的方法不同地处理类或实例对象。我如何获得类方法的列表?

还看到:

方法中的方法如何列出 Python 2.5模块? 循环在 Python / IronPython对象 方法 找到方法 对象有 我怎么看里面 Python对象? 我该怎么做 中对对象进行内省 Python 2. x ? 如何获得 对象的方法和的完整列表 属性? 找出 函数可以从类中获得 实例在python中?


当前回答

class CPerson:
    def __init__(self, age):
        self._age = age

    def run(self):
        pass

    @property
    def age(self): return self._age

    @staticmethod
    def my_static_method(): print("Life is short, you need Python")

    @classmethod
    def say(cls, msg): return msg


test_class = CPerson
# print(dir(test_class))  # list all the fields and methods of your object
print([(name, t) for name, t in test_class.__dict__.items() if type(t).__name__ == 'function' and not name.startswith('__')])
print([(name, t) for name, t in test_class.__dict__.items() if type(t).__name__ != 'function' and not name.startswith('__')])

输出

[('run', <function CPerson.run at 0x0000000002AD3268>)]
[('age', <property object at 0x0000000002368688>), ('my_static_method', <staticmethod object at 0x0000000002ACBD68>), ('say', <classmethod object at 0x0000000002ACF0B8>)]

其他回答

注意,您需要考虑是否希望结果中包含继承(但不重写)基类的方法。dir()和inspect.getmembers()操作包含基类方法,但使用__dict__属性不包含。

有这样一种方法:

[getattr(obj, m) for m in dir(obj) if not m.startswith('__')]

在处理类实例时,也许返回一个包含方法引用的列表,而不是仅仅返回名称¹会更好。如果这是你的目标,还有

使用不导入 从列表中排除私有方法(例如__init__)

这可能会有用。你可能还想确保它是可调用的(getattr(obj, m)),因为dir返回obj中的所有属性,而不仅仅是方法。

简而言之,对于一个班级来说

class Ghost:
    def boo(self, who):
        return f'Who you gonna call? {who}'

我们可以检查实例检索

>>> g = Ghost()
>>> methods = [getattr(g, m) for m in dir(g) if not m.startswith('__')]
>>> print(methods)
[<bound method Ghost.boo of <__main__.Ghost object at ...>>]

所以你可以马上调用它:

>>> for method in methods:
...     print(method('GHOSTBUSTERS'))
...
Who you gonna call? GHOSTBUSTERS

¹一个用例:

我使用它进行单元测试。有一个类,其中所有方法都执行相同过程的变体——这导致了冗长的测试,每个方法与其他方法之间只有细微的差别。DRY是一个遥远的梦想。

我想我应该有一个单一的测试所有的方法,所以我做了上面的迭代。

尽管我意识到我应该重构代码本身,无论如何都是符合dry的…这可能在未来仍然服务于一个随机的挑剔的灵魂。

要生成一个方法列表,请将方法名称放在一个列表中,不使用通常的括号。删除名称并附加圆括号,这将调用该方法。

    def methodA():
        print("@ MethodA")

    def methodB():
        print("@ methodB")

    a = []
    a.append(methodA)
    a.append(methodB)
    for item in a:
        item()

我只是把这个放在那里,因为排名靠前的答案不清楚。

这是一个简单的测试,不常用类基于Enum。

# -*- coding: utf-8 -*-
import sys, inspect
from enum import Enum

class my_enum(Enum):
    """Enum base class my_enum"""
    M_ONE = -1
    ZERO = 0
    ONE = 1
    TWO = 2
    THREE = 3

    def is_natural(self):
            return (self.value > 0)
    def is_negative(self):
            return (self.value < 0)

def is_clean_name(name):
    return not name.startswith('_') and not name.endswith('_')
def clean_names(lst):
    return [ n for n in lst if is_clean_name(n) ]
def get_items(cls,lst):
    try:
            res = [ getattr(cls,n) for n in lst ]
    except Exception as e:
            res = (Exception, type(e), e)
            pass
    return res


print( sys.version )

dir_res = clean_names( dir(my_enum) )
inspect_res = clean_names( [ x[0] for x in inspect.getmembers(my_enum) ] )
dict_res = clean_names( my_enum.__dict__.keys() )

print( '## names ##' )
print( dir_res )
print( inspect_res )
print( dict_res )

print( '## items ##' )
print( get_items(my_enum,dir_res) )
print( get_items(my_enum,inspect_res) )
print( get_items(my_enum,dict_res) )

这是输出结果。

3.7.7 (default, Mar 10 2020, 13:18:53) 
[GCC 9.2.1 20200306]
## names ##
['M_ONE', 'ONE', 'THREE', 'TWO', 'ZERO']
['M_ONE', 'ONE', 'THREE', 'TWO', 'ZERO', 'name', 'value']
['is_natural', 'is_negative', 'M_ONE', 'ZERO', 'ONE', 'TWO', 'THREE']
## items ##
[<my_enum.M_ONE: -1>, <my_enum.ONE: 1>, <my_enum.THREE: 3>, <my_enum.TWO: 2>, <my_enum.ZERO: 0>]
(<class 'Exception'>, <class 'AttributeError'>, AttributeError('name'))
[<function my_enum.is_natural at 0xb78a1fa4>, <function my_enum.is_negative at 0xb78ae854>, <my_enum.M_ONE: -1>, <my_enum.ZERO: 0>, <my_enum.ONE: 1>, <my_enum.TWO: 2>, <my_enum.THREE: 3>]

所以我们有:

Dir提供的数据不完整 检查。Getmembers提供不完整的数据,并提供getattr()无法访问的内部键。 __dict__.keys()提供完整可靠的结果

为什么投票如此错误?我错在哪里?其他答案的得票这么低的人哪里错了?

如果你只想列出一个python类的方法

import numpy as np
print(np.random.__all__)