Come posso ottenere un elenco di metodi in una classe Python?


331

1
La fonte ..... la fonte ...
RickyA

4
@JonCrowell non è così che funziona la Forza.
Ken Williams,

Per Cython usare la direttiva del compilatore bindingfunziona: stackoverflow.com/a/46041480/1959808
Ioannis Filippidis

4
Su python3: [f for f in dir(ClassName) if not f.startswith('_')]o semplicemente dir(ClassName)per tutto
Seraf

@Seraf Non inserire le risposte nei commenti. Pubblica invece una risposta.
wjandrea,

Risposte:


333

Un esempio (elencando i metodi della optparse.OptionParserclasse):

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

Si noti che getmembersrestituisce un elenco di 2 tuple. Il primo elemento è il nome del membro, il secondo elemento è il valore.

Puoi anche passare un'istanza a getmembers:

>>> parser = OptionParser()
>>> inspect.getmembers(parser, predicate=inspect.ismethod)
...

4
perfetto, la parte predicato è la chiave, altrimenti otterrai la stessa cosa di dict con le meta info extra. Grazie.
Purrell,

2
Questo produrrà un elenco di tutti i metodi nella classe (compresi quelli ereditati da altre classi) o elencherà solo i metodi che sono esplicitamente definiti in quella classe?
Anderson Green

10
inspect.isroutinepotrebbe essere un predicato più appropriato; inspect.ismethodnon funziona con tutti i metodi degli oggetti.
Gavin S. Yancey,

1
Funzionava solo quando si utilizzava un'istanza della classe (come pure nell'esempio). Questo comportamento è previsto?
Christian Reall-Fluharty,

2
su Python 3.7 almeno questo non funziona, devi istanziare la classe
kederrac l'

222

c'è il dir(theobject) metodo per elencare tutti i campi e i metodi del tuo oggetto (come una tupla) e il modulo inspect (come scrivere in codice) per elencare i campi e i metodi con il loro documento (in "" ").

Poiché tutto (persino i campi) potrebbe essere chiamato in Python, non sono sicuro che esista una funzione integrata per elencare solo i metodi. Potresti provare se l' oggetto che attraversi dirè richiamabile o meno.


3
dir (oggetto) è la soluzione più semplice che abbia mai usato.
lstodd,

@skjerns Ci vogliono 5 simboli per digitarlo. :)
Dr_Zaszuś

117

Python 3.x risponde senza librerie esterne

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

risultato escluso dunder:

method_list = [func for func in dir(Foo) if callable(getattr(Foo, func)) and not func.startswith("__")]

38

Supponi di voler conoscere tutti i metodi associati alla classe di elenco Digita semplicemente quanto segue

 print (dir(list))

Sopra ti darà tutti i metodi della classe list


2
Questa è la soluzione migliore
Zeeshan Ahmad l'

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

32

Prova la proprietà __dict__.


16
Penso che intendi dict . Ma questo elenca gli attributi dell'istanza, non i metodi.
me_e il

1
... non ha funzionato neanche per me. Dopo aver consultato la sintassi Markdown, penso di intendere __dict__.
me_e il

3
@me_e probabilmente stai facendo "self .__ dict__" o, più genericamente, chiamando la versione dell'istanza di __dict__. Comunque anche le classi hanno un __dict__e questo dovrebbe mostrare i metodi della classe :)
Seaux

21

puoi anche importare il FunctionType dai tipi e testarlo con 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']

Questo ha funzionato bene per me. Ho aggiunto and not x.startswith('_')alla fine della comprensione della lista il mio uso per ignorare __init__i metodi privati ​​e.
Christopher Pearson,

2
Puoi sbarazzarti di importdi FunctionTypeusando una lambda usa e getta con type():type(lambda:0)
Tersosauros,

isinstancesarebbe meglio di type(y) == FunctionTypequi.
Gloweye,

13

Si noti che è necessario considerare se si desidera includere metodi nei metodi di base ereditati (ma non sovrascritti) nel risultato. Le operazioni dir()e inspect.getmembers()includono i metodi della classe base, ma l'uso __dict__dell'attributo no.


3

Questo funziona anche:

mymodule.py

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

In un altro file

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

produzione:

['foo', 'bar']

Dai documenti di Python:

inspect.isroutine (oggetto)

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

Così

print find_defining_class(car, 'speedometer') 

Pensa a Python pagina 210


3
Rientro di 5? Capitalizzare le parole chiave? Spaziatura non pep8?
Florrie,

1
Non una volta arrivarono i nazisti della convenzione sulla codifica!
rbennell,

1
Come risponde alla domanda?
Aran-Fey,

2

C'è questo approccio:

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

Quando si ha a che fare con un'istanza di classe , forse sarebbe meglio restituire un elenco con i riferimenti al metodo anziché solo i nomi¹. Se questo è il tuo obiettivo, oltre che

  1. Utilizzando il n import
  2. Escludendo i metodi privati ​​(ad es. __init__) Dall'elenco

Potrebbe essere utile. In poche parole, per una classe come

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

Potremmo verificare il recupero dell'istanza con

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

Quindi puoi chiamarlo subito:

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

¹ Un caso d'uso:

L'ho usato per test unitari . Aveva una classe in cui tutti i metodi eseguivano variazioni dello stesso processo, il che portava a lunghi test, ognuno a un passo dall'altro. ASCIUTTO era un sogno lontano.

Ho pensato che avrei dovuto fare un singolo test per tutti i metodi, quindi ho fatto l'iterazione sopra.

Anche se mi sono reso conto che dovrei invece refactificare il codice stesso in modo che sia conforme a DRY in ogni caso ... questo potrebbe comunque servire un'anima nitida casuale in futuro.


2

Lo tengo lì, perché le risposte più votate non sono chiare .

Questo è un semplice test con classe non usuale basata su 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) )

E questi sono risultati di output.

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

Quindi quello che abbiamo:

  • dir fornire dati non completi
  • inspect.getmembers fornire dati non completi e fornire chiavi interne non accessibili getattr()
  • __dict__.keys()fornire un risultato completo e affidabile

Perché i voti sono così errati? E dove sbaglio? E dove sbagliano altre persone che rispondono hanno voti così bassi?


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

fornisce un elenco identico a

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

lo fa.


1

Puoi elencare tutti i metodi in una classe python usando il seguente codice

dir(className)

Ciò restituirà un elenco di tutti i nomi dei metodi nella classe


0

Se il tuo metodo è un metodo "normale" e non un statimethod, classmethodecc.
C'è un piccolo trucco che mi è venuto in mente -

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

Questo può essere esteso ad altri tipi di metodi cambiando "funzione" nella ifcondizione corrispondente.
Testato su Python 2.7.


1
Non sono sicuro del motivo per cui questo è stato sottoposto a downgrade ... in realtà ha risolto il problema che stavo avendo.
redspidermkv,

-1

So che questo è un vecchio post, ma ho appena scritto questa funzione e la lascerò qui nel caso qualcuno inciampa in cerca di una risposta:

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

Questo codice non fa ciò che intende pubblicare. Dare class_only o instance_only comporterà un elenco vuoto.
Oz123,

-2

Questa è solo un'osservazione. "encode" sembra essere un metodo per oggetti stringa

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

Tuttavia, se str1 viene ispezionato per i metodi, viene restituito un elenco vuoto

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

Quindi, forse mi sbaglio, ma il problema sembra non essere semplice.


1
'a'è un oggetto, il cui tipo è str. Puoi vederlo correndo type('a'). inspect.getmember()accetta un parametro di tipo, quindi è necessario chiamareinspect.getmember(str) per vedere cosa ti aspetti.
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('__')])

produzione

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

-4

Se si desidera elencare solo i metodi di una classe Python

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

1
Questo è un modulo, non una classe.
Aran-Fey,

@ Aran-Fey Viene applicato per ogni classe, tutto esiste in ogni classe
Rakesh Chaudhari

2
No, non lo fa. Non esiste nemmeno in tutti i moduli .
Aran-Fey,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.