Como obtenho uma lista de métodos em uma classe Python?


331

1
A fonte ..... a fonte ...
RickyA

4
@ JonCrowell, não é assim que a Força funciona.
Ken Williams

Para Cython, usando a diretiva compilador bindingfunciona: stackoverflow.com/a/46041480/1959808
Ioannis Filippidis

4
Em python3: [f for f in dir(ClassName) if not f.startswith('_')]ou apenas dir(ClassName)para tudo
Seraf

@Seraf Por favor, não poste respostas nos comentários. Poste uma resposta.
wjandrea 11/04

Respostas:


332

Um exemplo (listando os métodos da 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)
...

Observe que getmembersretorna uma lista de 2 tuplas. O primeiro item é o nome do membro, o segundo item é o valor.

Você também pode passar uma instância para getmembers:

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

4
perfeito, a parte do predicado é fundamental, caso contrário, você obtém a mesma coisa que dict com as informações meta adicionais. Obrigado.
21415 Purrell

2
Isso produzirá uma lista de todos os métodos da classe (incluindo aqueles herdados de outras classes) ou apenas listará os métodos explicitamente definidos nessa classe?
Anderson Green

10
inspect.isroutinepode ser um predicado mais apropriado; inspect.ismethodnão funciona para os métodos de todos os objetos.
Gavin S. Yancey

1
Isso funcionou apenas ao usar uma instância da classe (como o exemplo também). Esse comportamento é esperado?
Christian Reall-Fluharty

2
no python 3.7 pelo menos isso não funciona, você precisa instanciar a classe
kederrac

222

Existe o dir(theobject) método para listar todos os campos e métodos do seu objeto (como uma tupla) e o módulo inspecionar (como codeape write) para listar os campos e métodos com seus documentos (em "" ").

Como tudo (inclusive campos) pode ser chamado em Python, não tenho certeza se existe uma função interna para listar apenas métodos. Você pode tentar se o objeto que você obtém diré passível de chamada ou não.


3
dir (objeto) é a solução mais simples que já usei.
Lstodd

@skjerns São necessários 5 símbolos para digitá-lo. :)
Dr_Zaszuś

117

Resposta do Python 3.x sem bibliotecas externas

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

resultado excluído do dunder:

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

38

Digamos que você queira conhecer todos os métodos associados à classe de lista Apenas digite O seguinte

 print (dir(list))

Acima fornecerá todos os métodos da classe list


2
Esta é a melhor solução
Zeeshan Ahmad

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

32

Experimente a propriedade __dict__.


16
Eu acho que você quer dizer ditado . Mas isso lista os atributos da instância, não os métodos.
me_and

1
... isso não funcionou para mim também. Depois de consultar a sintaxe do Markdown, acho que quero dizer __dict__.
me_and

3
@me_and você provavelmente está fazendo "self .__ dict__" ou, de forma mais genérica, chamando a versão da instância de __dict__. No entanto classes têm um __dict__muito e que deve exibir os métodos de classe :)
Seaux

21

você também pode importar o FunctionType dos tipos e testá-lo com o 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']

Isto funcionou bem para mim. Eu adicionei and not x.startswith('_')ao final da lista a compreensão para o meu uso para ignorar __init__os métodos privados e.
Christopher Pearson

2
Você pode livrar-se do importde FunctionTypeusando um lambda descartável com type():type(lambda:0)
Tersosauros

isinstanceseria o melhor do que type(y) == FunctionTypeaqui.
Gloweye

13

Observe que você precisa considerar se deseja que os métodos das classes base herdadas (mas não substituídas) sejam incluídos no resultado. As operações dir()e inspect.getmembers()incluem métodos de classe base, mas o uso do __dict__atributo não.


3

Isso também funciona:

mymodule.py

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

Em outro arquivo

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

resultado:

['foo', 'bar']

Nos documentos python:

inspect.isroutine (objeto)

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

assim

print find_defining_class(car, 'speedometer') 

Think Python página 210


3
Recuo de 5? Como capitalizar palavras-chave? Espaçamento no estilo não-pep8?
Florrie

1
Nem uma vez que os nazis da convenção de codificação chegaram lá!
Rbennell

1
Como isso responde à pergunta?
Aran-Fey

2

Existe esta abordagem:

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

Ao lidar com uma instância de classe , talvez seja melhor retornar uma lista com as referências de método em vez de apenas nomes¹. Se esse é seu objetivo, além de

  1. Usando não import
  2. Excluindo métodos privados (por exemplo __init__) da lista

Pode ser útil. Em poucas palavras, para uma classe como

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

Poderíamos verificar a recuperação da instância com

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

Então você pode ligar imediatamente:

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

¹ Um caso de uso:

Eu usei isso para testes de unidade . Teve uma classe em que todos os métodos realizavam variações do mesmo processo - o que levava a testes demorados, cada um apenas um pouco diferente dos outros. DRY era um sonho distante.

Achei que deveria ter um único teste para todos os métodos, então fiz a iteração acima.

Embora eu tenha percebido que, em vez disso, deveria refatorar o código em si para ser compatível com DRY ... isso ainda pode servir uma alma nítida e aleatória no futuro.


2

Eu apenas mantenho isso lá, porque as respostas mais bem avaliadas não são claras .

Este é um teste simples com classe não usual baseada no 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 isso são resultados de saída.

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

Então, o que temos:

  • dir fornecer dados não completos
  • inspect.getmembers fornecer dados não completos e chaves internas que não são acessíveis com getattr()
  • __dict__.keys()forneça resultado completo e confiável

Por que os votos são tão errôneos? E onde eu estou errado? E onde outras pessoas erradas, que respondem, têm votos tão baixos?


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

fornece uma lista idêntica à

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

faz.


0

Se o seu método é um método "regular" e não um statimethod, classmethodetc.
Existe um pequeno truque que eu criei -

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

Isso pode ser estendido para outros tipos de métodos, alterando "função" na ifcondição correspondente.
Testado em python 2.7.


1
Não sei por que isso foi rebaixado ... ele realmente resolveu o problema que eu estava tendo.
redspidermkv 25/02

0

Você pode listar todos os métodos em uma classe python usando o seguinte código

dir(className)

Isso retornará uma lista de todos os nomes dos métodos na classe


-1

Eu sei que este é um post antigo, mas acabei de escrever esta função e a deixarei aqui, caso alguém tropece em busca de uma resposta:

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

Este código não faz o que se destina como publicado. Dar class_only ou instance_only resultará em lista vazia.
Oz123

-2

Isto é apenas uma observação. "codificar" parece ser um método para objetos de string

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

No entanto, se str1 for inspecionado para métodos, uma lista vazia será retornada

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

Então, talvez eu esteja errado, mas o problema parece não ser simples.


1
'a'É um objecto, cujo tipo é str. Você pode ver isso executando type('a'). inspect.getmember()usa um parâmetro de tipo, então você precisa ligar inspect.getmember(str)para ver o que espera.
lhasson 19/02

-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('__')])

resultado

[('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 você deseja listar apenas métodos de uma classe python

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

1
Isso é um módulo, não uma classe.
Aran-Fey

@ Aran-Fey É aplicado para todas as classes, tudo é existir em todas as classes
Rakesh Chaudhari

2
Não, não faz. Nem existe em todos os módulos .
`` #
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.