Як отримати список методів у класі Python?


330

1
Джерело ..... джерело ...
RickyA

4
@JonCrowell - це не так, як працює сила.
Кен Вільямс

Для Cython з допомогою директиви компілятора bindingпрацює: stackoverflow.com/a/46041480/1959808
Іоанніс Filippidis

4
На python3: [f for f in dir(ClassName) if not f.startswith('_')]або просто dir(ClassName)на все
Сераф

@Seraf Будь ласка, не публікуйте відповідей у ​​коментарях. Натомість надішліть відповідь.
wjandrea

Відповіді:


332

Приклад (перелік методів 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)
...

4
ідеально, частина предиката є ключовою, інакше ви отримуєте те саме, що і диктат із додатковою мета-інформацією. Дякую.
Перрелл

2
Чи створить це список усіх методів у класі (включаючи ті, які успадковані від інших класів), або він буде перераховувати лише методи, які чітко визначені в цьому класі?
Андерсон Зелений

10
inspect.isroutineможе бути більш підходящим присудком; inspect.ismethodпрацює не для всіх методів об'єктів.
Гавін С. Янцей

1
Це працювало лише при використанні екземпляра класу (як це робиться в прикладі). Це очікувана поведінка?
Крістіан Реал-Флухарті

2
на python 3.7 принаймні це не працює, ви повинні інстанціювати клас
kederrac

222

Існує dir(theobject)метод перерахування всіх полів і методів вашого об'єкта (у вигляді кортежу), а модуль перевірки (як запис кодексу) списку полів та методів з їх документом (у "" ").

Оскільки все (навіть поля) можуть бути викликані в 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("__")]

38

Скажіть, ви хочете знати всі методи, пов’язані з класом списку Просто введіть наступне

 print (dir(list))

Вище наведемо всі методи класу списку


2
Це найкраще рішення
Зеешан Ахмад

3
print([ m for m in dir(my_class) if not m.startswith('__')])
Evhz

32

Спробуйте власність __dict__.


16
Я думаю, ти маєш на увазі дікт . Але тут перераховані атрибути екземпляра, а не методи.
me_і

1
... це теж не працювало для мене. Порадившись із синтаксисом Markdown, я думаю, я маю на увазі __dict__.
me_і

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

Це добре спрацювало для мене. Я додав 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']

З Документів python:

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()забезпечують повний і надійний результат

Чому голоси такі помилкові? І де я помиляюся? А де помиляються інші люди, відповіді на яких мають такі низькі голоси?


1
methods = [(func, getattr(o, func)) for func in dir(o) if callable(getattr(o, func))]

дає ідентичний список як

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

робить.


0

Якщо ваш метод «звичайний» метод , а не statimethod, і classmethodт.д.
Існує трохи зламати я придумав -

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

Це можна поширити на інші типи методів, відповідно змінивши "функцію" в ifумові.
Випробуваний на python 2.7.


1
Не впевнений, чому це було знято ... Це насправді вирішило проблему, яку я мав.
redspidermkv

0

Ви можете перерахувати всі методи класу python, використовуючи наступний код

dir(className)

Це поверне список усіх назв методів у класі


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

Цей код не робить те, що призначено, як опубліковано. Надання 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>)]

-4

Якщо ви хочете перерахувати лише методи класу python

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

1
Це модуль, а не клас.
Аран-Фей

@ Aran-Fey Застосовується для кожного класу, все існує в кожному класі
Ракеш Чаудхарі

2
Ні, це не так. Він навіть не існує у всіх модулях .
Аран-Фей
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.