Jak uzyskać listę metod w klasie Python?

330

Chcę iterować po metodach w klasie lub obsługiwać obiekty klasy lub instancji inaczej w zależności od obecnych metod. Jak uzyskać listę metod klasowych?

Zobacz także:

Purrell
źródło
1
Źródło ..... źródło ...
RickyA
4
@JonCrowell nie tak działa Moc.
Ken Williams
W przypadku Cython korzystającego z dyrektywy kompilatora bindingdziała: stackoverflow.com/a/46041480/1959808
Ioannis Filippidis
4
Na python3: [f for f in dir(ClassName) if not f.startswith('_')]lub po prostu dir(ClassName)na wszystko
Seraf
@Seraf Proszę nie zamieszczać odpowiedzi w komentarzach. Zamiast tego opublikuj odpowiedź.
wjandrea

Odpowiedzi:

332

Przykład (zawierający listę metod optparse.OptionParserklasy):

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

Zauważ, że getmemberszwraca listę 2-krotek. Pierwszy element to nazwa członka, drugi element to wartość.

Możesz także przekazać instancję do getmembers:

>>> parser = OptionParser()
>>> inspect.getmembers(parser, predicate=inspect.ismethod)
...
Codeape
źródło
4
idealnie, część predykatowa jest kluczowa, w przeciwnym razie otrzymasz to samo, co dyktowanie z dodatkowymi informacjami meta. Dzięki.
Purrell,
2
Czy utworzy to listę wszystkich metod w klasie (w tym tych odziedziczonych po innych klasach), czy też wyświetli tylko te metody, które są wyraźnie zdefiniowane w tej klasie?
Anderson Green
10
inspect.isroutine może być bardziej odpowiednim orzeczeniem; inspect.ismethodnie działa dla metod wszystkich obiektów.
Gavin S. Yancey
1
Działa to tylko w przypadku korzystania z instancji klasy (podobnie jak w przykładzie). Czy to oczekiwane zachowanie?
Christian Reall-Fluharty,
2
na Pythonie 3.7 przynajmniej to nie działa, musisz utworzyć instancję klasy
kederrac
222

Istnieje dir(theobject)metoda wylistowania wszystkich pól i metod twojego obiektu (jako krotki) oraz moduł inspekcji (jako zapis kodu), aby wyświetlić listę pól i metod wraz z ich dokumentem (w „” „”).

Ponieważ wszystko (nawet pola) może być wywoływane w Pythonie, nie jestem pewien, czy istnieje wbudowana funkcja do wyświetlania tylko metod. Możesz spróbować, jeśli obiekt , przez który przejdziesz, dirmożna wywołać, czy nie.

Vincent Demeester
źródło
3
dir (obiekt) to najprostsze rozwiązanie, jakiego użyłem.
Istodd
@skjerns Do wpisania potrzeba 5 symboli. :)
Dr_Zaszuś
117

Odpowiedź na Python 3.x bez bibliotek zewnętrznych

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

wynik wykluczony z dundera:

method_list = [func for func in dir(Foo) if callable(getattr(Foo, func)) and not func.startswith("__")]
Derorrist
źródło
38

Powiedz, że chcesz poznać wszystkie metody związane z klasą listy. Wpisz następujące

 print (dir(list))

Powyżej podasz wszystkie metody klasy listy

Naresh Joshi
źródło
2
To najlepsze rozwiązanie
Zeeshan Ahmad
3
print([ m for m in dir(my_class) if not m.startswith('__')])
Evhz
32

Wypróbuj nieruchomość __dict__.

Eugene Bulkin
źródło
16
Myślę, że masz na myśli dyktę . Ale to pokazuje atrybuty instancji, a nie metody.
me_and
1
… To też nie działało dla mnie. Po zapoznaniu się ze składnią Markdown myślę, że mam na myśli __dict__.
me_and
3
@me_i prawdopodobnie wykonujesz „self .__ dict__” lub, bardziej ogólnie, wywołując wersję instancji __dict__. Jednak klasy też mają __dict__i powinny wyświetlać metody klasowe :)
Seaux
21

możesz również zaimportować FunctionType z typów i przetestować go za pomocą 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
źródło
To działało dla mnie dobrze. Dodałem and not x.startswith('_')do końca listy zrozumienie dla mojego użycia do ignorowania __init__metod prywatnych i.
Christopher Pearson
2
Można pozbyć się importz FunctionTypeprzy użyciu lambda wyrzucenie z type():type(lambda:0)
Tersosauros
isinstancebyłoby lepiej niż type(y) == FunctionTypetutaj.
Gloweye,
13

Zauważ, że musisz rozważyć, czy chcesz, aby metody z klas podstawowych, które są dziedziczone (ale nie przesłonięte), zostały uwzględnione w wyniku. dir()I inspect.getmembers()operacje zrobić to bazowych metod klasy, ale użycie __dict__atrybutu nie.

satyagraha
źródło
3

Działa to również:

mymodule.py

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

W innym pliku

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

wynik:

['foo', 'bar']

Z dokumentacji Pythona:

inspect.isroutine (obiekt)

Return true if the object is a user-defined or built-in function or method.
Josh Dando
źródło
2
def find_defining_class(obj, meth_name):
    for ty in type(obj).mro():
        if meth_name in ty.__dict__:
            return ty

Więc

print find_defining_class(car, 'speedometer') 

Pomyśl o języku Python na stronie 210

Lewis Scott Diamond
źródło
3
Wcięcie 5? Wielkie słowa kluczowe? Odstępy w stylu innym niż pep8?
Florrie,
1
Ani razu, gdy naziści dotarli do konwencji kodowania!
rbennell
1
Jak to odpowiada na pytanie?
Aran-Fey,
2

Istnieje takie podejście:

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

Kiedy mamy do czynienia z instancją klasy , być może lepiej byłoby zwrócić listę z referencjami do metod, a nie tylko z nazwami¹. Jeśli to twój cel, jak również

  1. Korzystanie z nr import
  2. Z wyłączeniem metod prywatnych (np. __init__) Z listy

Może się przydać. W skrócie, dla klasy takiej jak

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

Możemy sprawdzić pobieranie instancji za pomocą

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

Możesz więc od razu to nazwać:

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

¹ Przypadek użycia:

Użyłem tego do testów jednostkowych . Miał klasę, w której wszystkie metody przeprowadzały odmiany tego samego procesu - co prowadziło do długich testów, z których każda była tylko drobną modyfikacją. SUCHO było odległym snem.

Pomyślałem, że powinienem mieć jeden test dla wszystkich metod, więc zrobiłem powyższą iterację.

Chociaż zdałem sobie sprawę, że powinienem zrefakturować sam kod tak, aby był zgodny z DRY ... to może nadal służyć losowej, nikczemnej duszy w przyszłości.

Julio Cezar Silva
źródło
2

Po prostu trzymam to tam, ponieważ najwyżej oceniane odpowiedzi nie są jasne .

To prosty test z nietypową klasą opartą na 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) )

I to są wyniki wyjściowe.

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

Co mamy:

  • dir podać niekompletne dane
  • inspect.getmembers podać niekompletne dane i podać klucze wewnętrzne, które nie są dostępne za pomocą getattr()
  • __dict__.keys()zapewniają pełny i niezawodny wynik

Dlaczego głosy są tak błędne? A gdzie się mylę? A gdzie są inne osoby, które mają tak mało głosów?

kupiec
źródło
1
methods = [(func, getattr(o, func)) for func in dir(o) if callable(getattr(o, func))]

daje identyczną listę jak

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

robi.

Patrick B.
źródło
0

Jeśli twoja metoda jest metodą „zwykłą”, a nie itd. statimethod, classmethodWpadłem
na mały hack -

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

Można to rozszerzyć na inne metody, odpowiednio zmieniając „funkcję” w ifwarunku.
Testowane na Pythonie 2.7.

markroxor
źródło
1
Nie jestem pewien, dlaczego zostało to zanegowane ... to faktycznie rozwiązało problem, który miałem.
redspidermkv
0

Możesz wyświetlić listę wszystkich metod w klasie python, używając następującego kodu

dir(className)

Spowoduje to zwrócenie listy wszystkich nazw metod w klasie

Ekene Oguikpu
źródło
-1

Wiem, że to stary post, ale właśnie napisałem tę funkcję i zostawię ją tutaj, na wypadek, gdyby ktoś potknął się o odpowiedź:

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))
użytkownik3569372
źródło
Ten kod nie działa zgodnie z zamierzeniami opublikowanymi. Podanie class_only lub instance_only spowoduje, że lista będzie pusta.
Oz123
-2

To tylko spostrzeżenie. „kodowanie” wydaje się być metodą dla obiektów łańcuchowych

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

Jednak jeśli str1 jest sprawdzany pod kątem metod, zwracana jest pusta lista

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

Może się mylę, ale wydaje się, że problem nie jest prosty.

José Crespo Barrios
źródło
1
'a'to obiekt, którego typem jest str. Możesz to zobaczyć, uruchamiając type('a'). inspect.getmember()pobiera parametr typu, więc musisz zadzwonić, inspect.getmember(str)aby zobaczyć, czego oczekujesz.
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('__')])

wynik

[('run', <function CPerson.run at 0x0000000002AD3268>)]
[('age', <property object at 0x0000000002368688>), ('my_static_method', <staticmethod object at 0x0000000002ACBD68>), ('say', <classmethod object at 0x0000000002ACF0B8>)]
Carson
źródło
-4

Jeśli chcesz wyświetlić listę tylko metod klasy python

import numpy as np
print(np.random.__all__)
Rakesh Chaudhari
źródło
1
To moduł, a nie klasa.
Aran-Fey,
@ Aran-Fey Ma zastosowanie do każdej klasy, wszystko istnieje w każdej klasie
Rakesh Chaudhari
2
Nie, nie ma. Nie istnieje nawet we wszystkich modułach .
Aran-Fey,