Как получить список методов в классе Python?

331

Я хочу перебирать методы в классе или обрабатывать объекты класса или экземпляра по-разному в зависимости от имеющихся методов. Как мне получить список методов класса?

Также см:

Purrell
источник
1
Источник ..... источник ...
RickyA
4
@JonCrowell это не так, как работает сила.
Кен Уильямс
Для Cython использование директивы компилятора bindingработает: stackoverflow.com/a/46041480/1959808
Иоаннис Филиппидис
4
На python3: [f for f in dir(ClassName) if not f.startswith('_')]или только dir(ClassName)для всего
Сераф
@Seraf Пожалуйста, не оставляйте ответы в комментариях. Вместо этого отправьте ответ.
wjandrea

Ответы:

333

Пример (перечисление методов optparse.OptionParserкласса):

>>> from optparse import OptionParser
>>> import inspect
#python2
>>> inspect.getmembers(OptionParser, predicate=inspect.ismethod)
[([('__init__', <unbound method OptionParser.__init__>),
...
 ('add_option', <unbound method OptionParser.add_option>),
 ('add_option_group', <unbound method OptionParser.add_option_group>),
 ('add_options', <unbound method OptionParser.add_options>),
 ('check_values', <unbound method OptionParser.check_values>),
 ('destroy', <unbound method OptionParser.destroy>),
 ('disable_interspersed_args',
  <unbound method OptionParser.disable_interspersed_args>),
 ('enable_interspersed_args',
  <unbound method OptionParser.enable_interspersed_args>),
 ('error', <unbound method OptionParser.error>),
 ('exit', <unbound method OptionParser.exit>),
 ('expand_prog_name', <unbound method OptionParser.expand_prog_name>),
 ...
 ]
# python3
>>> inspect.getmembers(OptionParser, predicate=inspect.isfunction)
...

Обратите внимание, что getmembersвозвращает список из 2-х кортежей. Первый элемент - это имя члена, второй элемент - это значение.

Вы также можете передать экземпляр getmembers:

>>> parser = OptionParser()
>>> inspect.getmembers(parser, predicate=inspect.ismethod)
...
codeape
источник
4
идеально, часть предиката является ключевой, иначе вы получите то же самое, что и dict с дополнительной метаинформацией. Спасибо.
Purrell
2
Будет ли это производить список всех методов в классе (включая те, которые унаследованы от других классов), или это будет только список методов, которые явно определены в этом классе?
Андерсон Грин
10
inspect.isroutineможет быть более подходящим предикатом; inspect.ismethodне работает для всех методов объектов.
Гэвин С. Янси
1
Это работало только при использовании экземпляра класса (как и в примере). Это ожидаемое поведение?
Кристиан Реал-Флухарти
2
на Python 3.7 по крайней мере это не работает, вы должны создать экземпляр класса
kederrac
222

Здесь dir(theobject) метод для перечисления всех полей и методов вашего объекта (в виде кортежа) и модуль inspect (при записи codeape) для перечисления полей и методов с их документом (в "" ").

Поскольку все (даже поля) могут вызываться в Python, я не уверен, что есть встроенная функция для отображения только методов. Вы можете попробовать , если объект вы получите через dirэто отозван или нет.

Винсент Деместер
источник
3
dir (объект) - самое простое решение, которое я использовал.
lstodd
@skjerns Чтобы набрать его, нужно 5 символов. :)
Dr_Zaszuś
117

Python 3.x ответ без внешних библиотек

method_list = [func for func in dir(Foo) if callable(getattr(Foo, func))]

исключенный результат:

method_list = [func for func in dir(Foo) if callable(getattr(Foo, func)) and not func.startswith("__")]
Derorrist
источник
38

Скажем, вы хотите знать все методы, связанные с классом списка Просто введите следующее

 print (dir(list))

Выше приведу вам все методы списка класса

Нареш Джоши
источник
2
Это лучшее решение
Зеешан Ахмад
3
print([ m for m in dir(my_class) if not m.startswith('__')])
Евхз
32

Попробуйте собственность __dict__.

Евгений Булкин
источник
16
Я думаю, что вы имеете в виду диктат . Но здесь перечислены атрибуты экземпляра, а не методы.
me_and
1
... это не сработало для меня тоже. Изучив синтаксис Markdown, я думаю, что имею в виду __dict__.
me_and
3
@ me_и вы, вероятно, делаете "self .__ dict__" или, в более общем смысле, вызываете версию экземпляра __dict__. Однако у классов есть __dict__тоже, и это должно отображать методы класса :)
Seaux
21

Вы также можете импортировать FunctionType из типов и проверить его с помощью class.__dict__:

from types import FunctionType

class Foo:
    def bar(self): pass
    def baz(self): pass

def methods(cls):
    return [x for x, y in cls.__dict__.items() if type(y) == FunctionType]

methods(Foo)  # ['bar', 'baz']
Seaux
источник
Это хорошо сработало для меня. Я добавил and not x.startswith('_')в конец понимание списка для моего использования, чтобы игнорировать __init__и частные методы.
Кристофер Пирсон
2
Вы можете избавиться от importиз FunctionTypeс помощью лямбды с одноразовой type():type(lambda:0)
Tersosauros
isinstanceбудет лучше, чем type(y) == FunctionTypeздесь.
Gloweye
13

Обратите внимание, что вам нужно подумать, хотите ли вы, чтобы методы из базовых классов, которые наследуются (но не переопределяются), были включены в результат. dir()И inspect.getmembers()операции действительно включают методы базового класса, но использование __dict__атрибута нет.

сатьяграху
источник
3

Это также работает:

mymodule.py

def foo(x)
   return 'foo'
def bar()
   return 'bar'

В другом файле

import inspect
import mymodule
method_list = [ func[0] for func in inspect.getmembers(mymodule, predicate=inspect.isroutine) if callable(getattr(mymodule, func[0])) ]

вывод:

['foo', 'bar']

Из документации по питону:

inspect.isroutine (объект)

Return true if the object is a user-defined or built-in function or method.
Джош Дандо
источник
2
def find_defining_class(obj, meth_name):
    for ty in type(obj).mro():
        if meth_name in ty.__dict__:
            return ty

Так

print find_defining_class(car, 'speedometer') 

Подумайте Python страница 210

Льюис Скотт Даймонд
источник
3
Отступ 5? Ключевые слова с заглавной буквы? Интервал не в стиле pep8?
Флорри
1
Не раз нацистская конвенция попала к нему!
rbennell
1
Как это отвечает на вопрос?
Аран-Фей
2

Есть такой подход:

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

При работе с экземпляром класса , возможно, было бы лучше вернуть список со ссылками на методы, а не только с именами¹. Если это ваша цель, а также

  1. Использование нет import
  2. Исключение приватных методов (например __init__) из списка

Это может быть полезно. В двух словах, для такого класса, как

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

Case вариант использования:

Я использовал это для модульного тестирования . Был класс, где все методы выполняли вариации одного и того же процесса, что приводило к длительным тестам, каждый из которых был лишь в нескольких шагах от других. СУХОЙ был далекой мечтой.

Я подумал, что у меня должен быть один тест для всех методов, поэтому я сделал итерацию выше.

Хотя я понял, что вместо этого я должен реорганизовать сам код, чтобы он в любом случае был DRY-совместимым ... это все равно может послужить случайной душевной душе в будущем.

Хулио Цезарь Сильва
источник
2

Я просто держу это там, потому что ответы с самым высоким рейтингом не ясны .

Это простой тест с не обычным классом на основе 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 предоставить не полные данные
  • inspect.getmembers предоставить неполные данные и предоставить внутренние ключи, которые не доступны с getattr()
  • __dict__.keys()обеспечить полный и надежный результат

Почему голоса так ошибочны? И где я не прав? А где не правы другие люди, ответы на которые имеют столь низкие голоса?

imbearr
источник
1
methods = [(func, getattr(o, func)) for func in dir(o) if callable(getattr(o, func))]

дает идентичный список как

methods = inspect.getmembers(o, predicate=inspect.ismethod)

делает.

Патрик Б.
источник
1

Вы можете перечислить все методы в классе Python, используя следующий код

dir(className)

Это вернет список всех имен методов в классе

Ekene Oguikpu
источник
0

Если ваш метод «обычный» метод , а не statimethod, и classmethodт.д.
Существует немного взломать я придумал -

for k, v in your_class.__dict__.items():
    if "function" in str(v):
        print(k)

Это можно распространить на методы другого типа, изменив «функцию» в ifусловии соответственно.
Проверено на python 2.7.

markroxor
источник
1
Не уверен, почему за это проголосовали ... это действительно решило проблему, с которой я столкнулся.
redspidermkv
-1

Я знаю, что это старый пост, но только что написал эту функцию и оставлю ее здесь, если кто-то запинается в поисках ответа:

def classMethods(the_class,class_only=False,instance_only=False,exclude_internal=True):

    def acceptMethod(tup):
        #internal function that analyzes the tuples returned by getmembers tup[1] is the 
        #actual member object
        is_method = inspect.ismethod(tup[1])
        if is_method:
            bound_to = tup[1].im_self
            internal = tup[1].im_func.func_name[:2] == '__' and tup[1].im_func.func_name[-2:] == '__'
            if internal and exclude_internal:
                include = False
            else:
                include = (bound_to == the_class and not instance_only) or (bound_to == None and not class_only)
        else:
            include = False
        return include
    #uses filter to return results according to internal function and arguments
    return filter(acceptMethod,inspect.getmembers(the_class))
user3569372
источник
Этот код не делает то, что он предназначен для публикации. Предоставление class_only или instance_only приведет к пустому списку.
Oz123
-2

Это всего лишь наблюдение. «кодировать» кажется методом для строковых объектов

str_1 = 'a'
str_1.encode('utf-8')
>>> b'a'

Однако, если str1 проверяется на наличие методов, возвращается пустой список

inspect.getmember(str_1, predicate=inspect.ismethod)
>>> []

Так что, возможно, я ошибаюсь, но проблема вроде бы не простая.

Хосе Креспо Барриос
источник
1
'a'это объект, чей тип str. Вы можете увидеть это, запустив type('a'). inspect.getmember()принимает параметр типа, поэтому вам нужно позвонить, inspect.getmember(str)чтобы увидеть, что вы ожидаете.
lhasson
-3
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>)]
Carson
источник
-4

Если вы хотите перечислить только методы класса Python

import numpy as np
print(np.random.__all__)
Ракеш Чаудхари
источник
1
Это модуль, а не класс.
Аран-Фей
@ Aran-Fey Применяется для каждого класса, все существуют в каждом классе
Ракеш Чаудхари
2
Нет, это не так. Это даже не существует во всех модулях .
Аран-Фей