472 Stimmen

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

8voto

imbearr Punkte 979

Ich behalte das nur dort, weil die am besten bewerteten Antworten sind nicht eindeutig .

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 die Ergebnisse der Ausgabe.

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

Was wir also haben:

  • dir nicht vollständige Daten liefern
  • inspect.getmembers nicht vollständige Daten liefern und interne Schlüssel bereitstellen, auf die nicht mit getattr()
  • __dict__.keys() anbieten. vollständiges und zuverlässiges Ergebnis

Warum sind die Abstimmungen so fehlerhaft? Und wo liege ich falsch? Und wo irren sich andere Leute, deren Antworten so wenig Stimmen haben?

7voto

Josh Dando Punkte 1186

Das funktioniert auch:

En 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(object)

Gibt true zurück, wenn das Objekt eine benutzerdefinierte oder eingebaute Funktion oder Methode ist.

6voto

Julio Cezar Silva Punkte 1640

Es gibt diesen Ansatz:

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

Beim Umgang mit einer Klasse Instanz wäre es vielleicht besser, eine Liste mit den Methodenreferenzen zurückzugeben, anstatt nur Namen¹. Wenn das Ihr Ziel ist, sowie

  1. Keine Verwendung import
  2. Ausgenommen sind private Methoden (z. B. __init__ ) aus der Liste

Es könnte von Nutzen sein. Sie könnten auch sicherstellen wollen, dass es callable(getattr(obj, m)) da dir gibt alle Attribute innerhalb von obj und nicht nur Methoden.

Kurz gesagt, für eine Klasse wie

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

Wir könnten den Abruf der Instanz mit

>>> 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 ihn also sofort anrufen:

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

¹ Ein Anwendungsfall:

Ich habe dies für Unit-Tests . Ich hatte eine Klasse, in der alle Methoden Variationen desselben Prozesses durchführten - was zu langwierigen Tests führte, bei denen jede Methode nur eine Nuance von den anderen abwich. DRY war ein weit entfernter Traum.

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

Obwohl mir klar wurde, dass ich stattdessen die der Code selbst um trotzdem DRY-konform zu sein... das kann in Zukunft immer noch einer zufälligen pingeligen Seele dienen.

3voto

Patrick B. Punkte 11105
methods = [(func, getattr(o, func)) for func in dir(o) if callable(getattr(o, func))]

ergibt eine identische Liste wie

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

tut.

3voto

Sameer Ali VP Punkte 21

Sie können eine Funktion verwenden, die ich erstellt habe.

def method_finder(classname):

    non_magic_class = []

    class_methods = dir(classname)

    for m in class_methods:

        if m.startswith('__'):

            continue

        else:

            non_magic_class.append(m)

    return non_magic_class

method_finder(list)

Ausgabe:

['append',
 'clear',
 'copy',
 'count',
 'extend',
 'index',
 'insert',
 'pop',
 'remove',
 'reverse',
 'sort']

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X