Comment obtenir la liste des méthodes dans une classe Python?

331

Je veux parcourir les méthodes d'une classe ou gérer les objets de classe ou d'instance différemment en fonction des méthodes présentes. Comment obtenir une liste des méthodes de classe?

Regarde aussi:

Purrell
la source
1
La source ..... la source ...
RickyA
4
@JonCrowell, ce n'est pas ainsi que la Force fonctionne.
Ken Williams
Pour Cython, l'utilisation de la directive du compilateur bindingfonctionne: stackoverflow.com/a/46041480/1959808
Ioannis Filippidis
4
Sur python3: [f for f in dir(ClassName) if not f.startswith('_')]ou juste dir(ClassName)pour tout
Seraf
@Seraf Veuillez ne pas poster de réponses dans les commentaires. Postez plutôt une réponse.
wjandrea

Réponses:

333

Un exemple (listant les méthodes de la 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)
...

Notez que getmembersretourne une liste de 2 tuples. Le premier élément est le nom du membre, le deuxième élément est la valeur.

Vous pouvez également transmettre une instance à getmembers:

>>> parser = OptionParser()
>>> inspect.getmembers(parser, predicate=inspect.ismethod)
...
codeape
la source
4
parfait, la partie prédicat est la clé, sinon vous obtenez la même chose que dict avec les méta-informations supplémentaires. Merci.
Purrell
2
Cela produira-t-il une liste de toutes les méthodes de la classe (y compris celles qui sont héritées d'autres classes), ou listera-t-il uniquement les méthodes qui sont explicitement définies dans cette classe?
Anderson Green
10
inspect.isroutinepourrait être un prédicat plus approprié; inspect.ismethodne fonctionne pas pour toutes les méthodes des objets.
Gavin S. Yancey
1
Cela ne fonctionnait que lors de l'utilisation d'une instance de la classe (comme le fait également l'exemple). Est-ce un comportement attendu?
Christian Reall-Fluharty
2
sur python 3.7 au moins, cela ne fonctionne pas, vous devez instancier la classe
kederrac
222

Il y a la dir(theobject)méthode pour lister tous les champs et méthodes de votre objet (en tant que tuple) et le module inspect (en écriture codeape) pour lister les champs et méthodes avec leur doc (en "" ").

Parce que tout (même les champs) peut être appelé en Python, je ne suis pas sûr qu'il existe une fonction intégrée pour répertorier uniquement les méthodes. Vous voudrez peut-être essayer si l' objet que vous traversez direst appelable ou non.

Vincent Demeester
la source
3
dir (objet) est la solution la plus simple que j'ai utilisée.
lstodd du
@skjerns Il faut 5 symboles pour le taper. :)
Dr_Zaszuś
117

Réponse Python 3.x sans bibliothèques externes

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

résultat exclu du dunder:

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

Dites que vous voulez connaître toutes les méthodes associées à la classe de liste

 print (dir(list))

Ci-dessus vous donnera toutes les méthodes de classe de liste

Naresh Joshi
la source
2
Celui-ci est la meilleure solution
Zeeshan Ahmad
3
print([ m for m in dir(my_class) if not m.startswith('__')])
Evhz
32

Essayez la propriété __dict__.

Eugene Bulkin
la source
16
Je pense que tu veux dire dict . Mais cela répertorie les attributs de l'instance, pas les méthodes.
me_and
1
… Ça n'a pas marché pour moi non plus. Après avoir consulté la syntaxe Markdown, je pense que je veux dire __dict__.
me_and
3
@me_et vous faites probablement "self .__ dict__" ou, plus généralement, appelez la version d'instance de __dict__. Cependant les classes en ont __dict__aussi et cela devrait afficher les méthodes de classe :)
Seaux
21

vous pouvez également importer le FunctionType à partir de types et le tester avec 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
la source
Cela a bien fonctionné pour moi. J'ai ajouté and not x.startswith('_')à la fin de la liste la compréhension pour mon utilisation pour ignorer __init__les méthodes privées et.
Christopher Pearson
2
Vous pouvez vous débarrasser de importde FunctionTypel'aide d' un lambda avec jetable type():type(lambda:0)
Tersosauros
isinstanceserait mieux type(y) == FunctionTypequ'ici.
Gloweye
13

Notez que vous devez déterminer si vous souhaitez que les méthodes des classes de base héritées (mais non substituées) soient incluses dans le résultat. Les opérations dir()et inspect.getmembers()incluent des méthodes de classe de base, mais pas l'utilisation de l' __dict__attribut.

satyagraha
la source
3

Cela fonctionne également:

mymodule.py

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

Dans un autre fichier

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

production:

['foo', 'bar']

Depuis les documents python:

inspect.isroutine (objet)

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

Alors

print find_defining_class(car, 'speedometer') 

Pensez Python page 210

lewis scott diamond
la source
3
Indentation de 5? Capitaliser les mots clés? Espacement sans style pep8?
Florrie
1
Pas une fois que les nazis de la convention de codage y sont arrivés!
rbennell
1
Comment cela répond-il à la question?
Aran-Fey
2

Il y a cette approche:

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

Lorsqu'il s'agit d'une instance de classe , il serait peut-être préférable de renvoyer une liste avec les références de méthode au lieu de simplement des noms¹. Si tel est votre objectif, ainsi que

  1. Utiliser non import
  2. Exclusion de méthodes privées (par exemple __init__) de la liste

Cela peut être utile. En un mot, pour une classe comme

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

Nous pourrions vérifier la récupération d'instance avec

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

Vous pouvez donc l'appeler tout de suite:

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

¹ Un cas d'utilisation:

Je l'ai utilisé pour les tests unitaires . Il y avait une classe où toutes les méthodes effectuaient des variations du même processus - ce qui conduisait à de longs tests, chacun à seulement un coup d'œil des autres. SEC était un rêve lointain.

Je pensais que je devrais avoir un seul test pour toutes les méthodes, j'ai donc fait l'itération ci-dessus.

Bien que je me sois rendu compte que je devrais à la place refactoriser le code lui-même pour qu'il soit conforme à DRY de toute façon ... cela pourrait encore servir une âme au hasard à l'avenir.

Julio Cezar Silva
la source
2

Je garde cela là, car les réponses les mieux notées ne sont pas claires .

Il s'agit d'un test simple avec une classe inhabituelle basée sur 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) )

Et ce sont les résultats de sortie.

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

Donc ce que nous avons:

  • dir fournir des données incomplètes
  • inspect.getmembers fournir des données incomplètes et fournir des clés internes qui ne sont pas accessibles avec getattr()
  • __dict__.keys()fournir un résultat complet et fiable

Pourquoi les votes sont-ils si erronés? Et où je me trompe? Et où se trompent les autres personnes qui répondent ont des votes si bas?

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

donne une liste identique à

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

Est-ce que.

Patrick B.
la source
1

Vous pouvez répertorier toutes les méthodes d'une classe python à l'aide du code suivant

dir(className)

Cela renverra une liste de tous les noms des méthodes de la classe

Ekene Oguikpu
la source
0

Si votre méthode est une méthode "régulière" et non pas une statimethod, classmethodetc.
Il y a un petit hack que j'ai trouvé -

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

Cela peut être étendu à d'autres types de méthodes en changeant "fonction" dans la ifcondition en conséquence.
Testé sur python 2.7.

markroxor
la source
1
Je ne sais pas pourquoi cela a été rejeté ... cela a en fait résolu le problème que j'avais.
redspidermkv
-1

Je sais que c'est un ancien article, mais je viens d'écrire cette fonction et je la laisserai ici au cas où quelqu'un trébucherait à la recherche d'une réponse:

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
la source
Ce code ne fait pas ce qu'il est censé être publié. Si vous donnez class_only ou instance_only, la liste sera vide.
Oz123
-2

Ce n'est qu'une observation. "encoder" semble être une méthode pour les objets chaîne

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

Cependant, si str1 est inspecté pour les méthodes, une liste vide est retournée

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

Alors, je me trompe peut-être, mais le problème ne semble pas simple.

José Crespo Barrios
la source
1
'a'est un objet dont le type est str. Vous pouvez le voir en exécutant type('a'). inspect.getmember()prend un paramètre de type, vous devez donc appeler inspect.getmember(str)pour voir ce que vous attendez.
lhasson le
-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('__')])

production

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

Si vous souhaitez répertorier uniquement les méthodes d'une classe python

import numpy as np
print(np.random.__all__)
Rakesh Chaudhari
la source
1
C'est un module, pas une classe.
Aran-Fey
@ Aran-Fey Il est appliqué pour chaque classe, tout existe dans chaque classe
Rakesh Chaudhari
2
Non, non. Il n'existe même pas dans tous les modules .
Aran-Fey