Wie erhalte ich eine Liste der Methoden in einer Python-Klasse?

329

Ich möchte die Methoden in einer Klasse durchlaufen oder Klassen- oder Instanzobjekte basierend auf den vorhandenen Methoden unterschiedlich behandeln. Wie erhalte ich eine Liste der Klassenmethoden?

Siehe auch:

Purrell
quelle
1
Die Quelle ..... die Quelle ...
RickyA
4
@ JonCrowell So funktioniert die Macht nicht.
Ken Williams
Für Cython bindingfunktioniert die Verwendung der Compiler-Direktive : stackoverflow.com/a/46041480/1959808
Ioannis Filippidis
4
Auf Python3: [f for f in dir(ClassName) if not f.startswith('_')]oder einfach dir(ClassName)für alles
Seraf
@ Seraf Bitte poste keine Antworten in den Kommentaren. Schreiben Sie stattdessen eine Antwort.
Wjandrea

Antworten:

331

Ein Beispiel (Auflistung der Methoden der optparse.OptionParserKlasse):

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

Beachten Sie, dass getmemberseine Liste mit 2 Tupeln zurückgegeben wird. Das erste Element ist der Name des Mitglieds, das zweite Element ist der Wert.

Sie können eine Instanz auch übergeben an getmembers:

>>> parser = OptionParser()
>>> inspect.getmembers(parser, predicate=inspect.ismethod)
...
Codeape
quelle
4
Perfekt, der Prädikat-Teil ist der Schlüssel, ansonsten erhalten Sie das Gleiche wie das Diktat mit den zusätzlichen Meta-Informationen. Vielen Dank.
Purrell
2
Wird dadurch eine Liste aller Methoden in der Klasse erstellt (einschließlich derjenigen, die von anderen Klassen geerbt wurden), oder werden nur die Methoden aufgelistet, die in dieser Klasse explizit definiert sind?
Anderson Green
10
inspect.isroutinekönnte ein geeigneteres Prädikat sein; inspect.ismethodfunktioniert nicht für alle Objektmethoden.
Gavin S. Yancey
1
Dies funktionierte nur bei Verwendung einer Instanz der Klasse (wie auch im Beispiel). Ist das erwartetes Verhalten?
Christian Reall-Fluharty
2
unter python 3.7 funktioniert das zumindest nicht, man muss die klasse instanziieren
kederrac
222

Es gibt die dir(theobject)Methode zum Auflisten aller Felder und Methoden Ihres Objekts (als Tupel) und das Inspect-Modul (als Codeape Write) zum Auflisten der Felder und Methoden mit ihrem Dokument (in "" ").

Da in Python möglicherweise alles (auch Felder) aufgerufen wird, bin ich mir nicht sicher, ob es eine integrierte Funktion gibt, mit der nur Methoden aufgelistet werden können. Sie könnten versuchen wollen , wenn das Objekt Sie erhalten durch dirist aufrufbar oder nicht.

Vincent Demeester
quelle
3
dir (Objekt) ist die einfachste Lösung, die ich verwendet habe.
lstodd
1
Wie unterscheidet sich dies von der akzeptierten Lösung?
Skjerns
@skjerns Es werden 5 Symbole benötigt, um es einzugeben. :)
Dr_Zaszuś
117

Python 3.x-Antwort ohne externe Bibliotheken

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

dunder-ausgeschlossenes Ergebnis:

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

Angenommen, Sie möchten alle Methoden kennen, die der Listenklasse zugeordnet sind. Geben Sie einfach Folgendes ein

 print (dir(list))

Oben finden Sie alle Methoden der Listenklasse

Naresh Joshi
quelle
2
Dies ist die beste Lösung
Zeeshan Ahmad
3
print([ m for m in dir(my_class) if not m.startswith('__')])
Evhz
32

Probieren Sie die Eigenschaft __dict__.

Eugene Bulkin
quelle
16
Ich denke du meinst diktieren . Aber das listet die Attribute der Instanz auf, nicht die Methoden.
me_and
1
… Das hat auch bei mir nicht funktioniert. Nachdem ich die Markdown-Syntax konsultiert habe, meine ich __dict__.
me_and
3
@me_und Sie machen wahrscheinlich "self .__ dict__" oder rufen allgemeiner die Instanzversion von auf __dict__. Allerdings haben Klassen auch eine __dict__und das sollte die Klassenmethoden anzeigen :)
Seaux
21

Sie können den FunctionType auch aus Typen importieren und mit folgenden Tests testen 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
quelle
Das hat bei mir gut funktioniert. Ich habe and not x.startswith('_')am Ende der Liste das Verständnis hinzugefügt , damit ich die __init__privaten und privaten Methoden ignorieren kann.
Christopher Pearson
2
Sie können von der loszuwerden importder FunctionTypemit unter Verwendung einer Wegwerf - Lambda type():type(lambda:0)
Tersosauros
isinstancewäre besser als type(y) == FunctionTypehier.
Gloweye
13

Beachten Sie, dass Sie überlegen müssen, ob Methoden von Basisklassen, die geerbt (aber nicht überschrieben) werden sollen, in das Ergebnis aufgenommen werden sollen. Die Operationen dir()und inspect.getmembers()enthalten Basisklassenmethoden, die Verwendung des __dict__Attributs jedoch nicht.

Satyagraha
quelle
3

Dies funktioniert auch:

mymodule.py

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

In einer anderen Datei

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

Ausgabe:

['foo', 'bar']

Aus den Python-Dokumenten:

inspect.isroutine (Objekt)

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

Damit

print find_defining_class(car, 'speedometer') 

Denken Sie an Python Seite 210

Lewis Scott Diamond
quelle
3
Einrückung von 5? Schlüsselwörter groß schreiben? Nicht-pep8-artiger Abstand?
Florrie
1
Nicht einmal die Kodierungskonvention Nazis haben es geschafft!
Rbennell
1
Wie beantwortet dies die Frage?
Aran-Fey
2

Es gibt diesen Ansatz:

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

Im Umgang mit einer Klasse Beispiel , vielleicht würde es besser sein , anstatt nur names¹ eine Liste mit den Verfahren Referenzen zurückzukehren. Wenn das auch dein Ziel ist

  1. Mit Nr import
  2. Ausgenommen private Methoden (z __init__ ) von der Liste

Es kann von Nutzen sein. Kurz gesagt, für eine Klasse wie

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

Wir könnten den Instanzabruf mit überprüfen

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

Sie können es also sofort anrufen:

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

¹ Ein Anwendungsfall:

Ich habe dies für Unit-Tests verwendet . Hatte eine Klasse, in der alle Methoden Variationen desselben Prozesses durchführten - was zu langwierigen Tests führte, von denen jeder nur eine Optimierung von den anderen entfernt war. TROCKEN war ein weit entfernter Traum.

Ich dachte, ich sollte einen einzigen Test für alle Methoden haben, also habe ich die obige Iteration durchgeführt.

Obwohl mir klar wurde, dass ich stattdessen den Code selbst so umgestalten sollte , dass er sowieso DRY-konform ist ... könnte dies auch in Zukunft einer zufälligen, pingeligen Seele dienen.

Julio Cezar Silva
quelle
2

Ich behalte das einfach dort, weil die am besten bewerteten Antworten nicht klar sind .

Dies ist ein einfacher Test mit einer nicht üblichen Klasse, die auf Enum basiert.

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

Und das sind Ausgabeergebnisse.

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

Also was wir haben:

  • dir Geben Sie keine vollständigen Daten an
  • inspect.getmembers Geben Sie nicht vollständige Daten und interne Schlüssel an, auf die nicht zugegriffen werden kann getattr()
  • __dict__.keys()liefern vollständige und zuverlässige Ergebnisse

Warum sind Stimmen so falsch? Und wo irre ich mich? Und wo falsch andere Leute, deren Antworten so niedrige Stimmen haben?

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

gibt eine identische Liste wie

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

tut.

Patrick B.
quelle
0

Wenn Ihre Methode eine „normale“ Verfahren und nicht um eine statimethod, classmethodusw.
Es gibt einen kleinen Hack kam ich mit -

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

Dies kann auf andere Arten von Methoden erweitert werden, indem "Funktion" in der ifBedingung entsprechend geändert wird.
Getestet auf Python 2.7.

Markroxor
quelle
1
Ich bin mir nicht sicher, warum dies abgelehnt wurde ... es hat tatsächlich das Problem gelöst, das ich hatte.
redspidermkv
0

Sie können alle Methoden in einer Python-Klasse mithilfe des folgenden Codes auflisten

dir(className)

Dies gibt eine Liste aller Namen der Methoden in der Klasse zurück

Ekene Oguikpu
quelle
-1

Ich weiß, dass dies ein alter Beitrag ist, habe aber gerade diese Funktion geschrieben und werde sie hier belassen, falls jemand stolpert und nach einer Antwort sucht:

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
quelle
Dieser Code macht nicht das, was er als veröffentlicht beabsichtigt hat. Wenn Sie nur class_only oder instance_only angeben, wird die Liste leer.
Oz123
-2

Dies ist nur eine Beobachtung. "encode" scheint eine Methode für String-Objekte zu sein

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

Wenn str1 jedoch auf Methoden überprüft wird, wird eine leere Liste zurückgegeben

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

Vielleicht irre ich mich, aber das Problem scheint nicht einfach zu sein.

José Crespo Barrios
quelle
1
'a'ist ein Objekt, dessen Typ ist str. Sie können dies sehen, indem Sie ausführen type('a'). inspect.getmember()Nimmt einen Typparameter, müssen Sie aufrufen, um inspect.getmember(str)zu sehen, was Sie erwarten.
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('__')])

Ausgabe

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

Wenn Sie nur Methoden einer Python-Klasse auflisten möchten

import numpy as np
print(np.random.__all__)
Rakesh Chaudhari
quelle
1
Das ist ein Modul, keine Klasse.
Aran-Fey
@ Aran-Fey Es wird für jede Klasse angewendet, alles ist in jeder Klasse vorhanden
Rakesh Chaudhari
2
Nein, das tut es nicht. Es existiert nicht einmal in allen Modulen .
Aran-Fey