Wie überprüfe ich, ob eine Methode in Python vorhanden ist?

83

__getattr__()Wenn in der Funktion eine referenzierte Variable nicht gefunden wird, wird ein Fehler ausgegeben. Wie kann ich überprüfen, ob eine Variable oder Methode als Teil eines Objekts vorhanden ist?

import string
import logging

class Dynamo:
 def __init__(self,x):
  print "In Init def"
  self.x=x
 def __repr__(self):
  print self.x
 def __str__(self):
  print self.x
 def __int__(self):
  print "In Init def"
 def __getattr__(self, key):
    print "In getattr"
    if key == 'color':
        return 'PapayaWhip'
    else:
        raise AttributeError


dyn = Dynamo('1')
print dyn.color
dyn.color = 'LemonChiffon'
print dyn.color
dyn.__int__()
dyn.mymethod() //How to check whether this exist or not
Rajeev
quelle

Antworten:

91

Wie wäre es dir()vorher mit Funktion getattr()?

>>> "mymethod" in dir(dyn)
True
Michał Šrajer
quelle
7
Dies prüft nicht, ob es sich um eine Methode oder eine Variable handelt
hek2mgl
1
Die Verwendung von dir ist nicht großartig - es bestätigt nicht, dass der Name eine Methode ist
Tony Suffolk 66
109

Es ist einfacher, um Vergebung zu bitten, als um Erlaubnis.

Überprüfen Sie nicht, ob eine Methode vorhanden ist. Verschwenden Sie keine einzige Codezeile beim "Überprüfen"

try:
    dyn.mymethod() # How to check whether this exists or not
    # Method exists and was used.  
except AttributeError:
    # Method does not exist; What now?
S.Lott
quelle
57
Aber vielleicht will er es wirklich nicht nennen, nur um zu überprüfen, ob es diese Methode gibt (wie es in meinem Fall ist) ...
Flavius
49
Beachten Sie, dass dies fehlschlägt, wenn ein dyn.mymethod()Selbst AttributeErrorausgelöst wird.
DK
10
Wie @DK sagt, wird dadurch jeder AttributeError abgefangen, der durch die zu prüfende Methode ausgelöst wird, was möglicherweise unerwünscht ist (ganz zu schweigen davon, dass dies in diesem Fall fälschlicherweise auf das Fehlen der Methode schließen lässt).
ShreevatsaR
3
Im Prinzip gut, und Python hat im Gegensatz zu anderen Sprachen eine "Ausnahmen als Kontrollfluss" -Kultur. Wenn Sie jedoch Ausnahmeprotokollierungstools wie Sentry / Raven oder New Relic verwenden, müssen solche Ausnahmen einzeln herausgefiltert werden (sofern dies möglich ist) oder Rauschen erzeugen. Ich würde lieber prüfen, ob die Methode existiert, als sie aufzurufen.
RichVel
2
Das ist auf so vielen Ebenen falsch. Die Methode selbst kann AttributeError auslösen und dies wird erkannt, da die Methode nicht existiert! Es ruiniert auch die Debugger-Unterstützung, um Ausnahmen zu unterbrechen. Ich bin mir auch sicher, dass dies wahrscheinlich die Leistung beeinträchtigt, wenn sich etwas in einer Schleife befindet. Last but not list Ich möchte möglicherweise keine Methode ausführen, sondern nur überprüfen, ob sie vorhanden ist. Sie sollten in Betracht ziehen, diese Antwort zu entfernen oder zumindest alle diese Warnungen zu setzen, damit naive Leute nicht irregeführt werden.
Shital Shah
107

Überprüfen Sie, ob die Klasse eine solche Methode hat?

hasattr(Dynamo, key) and callable(getattr(Dynamo, key))

oder

hasattr(Dynamo, 'mymethod') and callable(getattr(Dynamo, 'mymethod'))

Sie können self.__class__anstelle von verwendenDynamo

seriyPS
quelle
23
Noneist nicht aufrufbar, also könnten Sie einfach tun callable(getattr(Dynamo, 'mymethod', None)). Ich habe diese Antwort verwendet, weil meine super (). Mymethod () werfen konnteAttributeError
sbutler
@sbutler Interessant, dass das funktioniert. Laut PyCharm ist die Signatur für getattr vermutlich def getattr(object, name, default=None):nicht korrekt, da ich sonst erwarten würde, None als dritten Parameter zu übergeben, um das Verhalten der Funktion nicht zu ändern.
bszom
@bszom: In einer Python-Shell help(getattr)heißt es: "Wenn ein Standardargument angegeben wird, wird es zurückgegeben, wenn das Attribut nicht vorhanden ist. Ohne dieses Argument wird in diesem Fall eine Ausnahme ausgelöst ." - (und Sie können in der Tat überprüfen, ob getattr eine Ausnahme auslöst, wenn das Attribut fehlt). So klar, was auch immer PyCharm ist, es ist falsch.
ShreevatsaR
@ShreevatsaR Danke, dass du meinen Verdacht bestätigt hast. PyCharm ist eine IDE.
BSZOM
4
EINFACHERE VERSION: Wenn Sie überprüfen möchten, ob die aktuelle Klasse INSTANCE ein Attribut hat und aufrufbar ist, gehen Sie wie folgt vor : if hasattr(self, "work") and callable(self.work). Dies prüft, ob die Instanz ein Arbeitsattribut hat (kann entweder eine Variable oder eine Funktion sein), und prüft dann, ob es aufrufbar ist (was bedeutet, dass es eine Funktion ist).
Mitch McMabers
14

Sie können versuchen, das Inspektionsmodul zu verwenden:

import inspect
def is_method(obj, name):
    return hasattr(obj, name) and inspect.ismethod(getattr(obj, name))

is_method(dyn, 'mymethod')
vint83
quelle
12

Ich benutze unten Dienstprogrammfunktion. Es funktioniert mit Lambda, Klassenmethoden sowie Instanzmethoden.

Dienstprogrammmethode

def has_method(o, name):
    return callable(getattr(o, name, None))

Beispiel Verwendung

Definieren wir die Testklasse

class MyTest:
  b = 'hello'
  f = lambda x: x

  @classmethod
  def fs():
    pass
  def fi(self):
    pass

Jetzt können Sie versuchen,

>>> a = MyTest()                                                    
>>> has_method(a, 'b')                                         
False                                                          
>>> has_method(a, 'f')                                         
True                                                           
>>> has_method(a, 'fs')                                        
True                                                           
>>> has_method(a, 'fi')                                        
True                                                           
>>> has_method(a, 'not_exist')                                       
False                                                          
Shital Shah
quelle
2
Diese Antwort ist (zumindest meiner Meinung nach) geeigneter als andere Antworten, da sie keinen allgemeinen Ansatz (unter Verwendung einer tryAnweisung) verwendet und prüft, wann immer das Mitglied eine tatsächliche Funktion ist. toller Anteil!
ymz
4

Wie wäre es damit nachzuschlagen dyn.__dict__?

try:
    method = dyn.__dict__['mymethod']
except KeyError:
    print "mymethod not in dyn"
deStrangis
quelle
Unterstrichpräfixierte Methoden bedeuten gemäß Konvention "privat".
xtofl
Double-Underbar-Präfix plus Double-Underbar-Suffix bedeutet "Dies wird normalerweise vom Python-Interpreter selbst verwendet". In der Regel gibt es eine Möglichkeit, den gleichen Effekt aus dem Programm eines Benutzers für die häufigsten Anwendungsfälle zu erzielen (in diesem Fall wäre dies der Fall) Verwenden der Punktnotation für ein Attribut), aber es ist weder verboten noch falsch, es zu verwenden, wenn Ihr Anwendungsfall dies wirklich erfordert.
DeStrangis
Es ist nicht verboten. Das Unrecht ist subjektiv: Es hängt davon ab, wie sehr Sie Programmierer verwirren möchten, die Konventionen einhalten: Verwenden Sie es nur, wenn Sie keine Alternative haben.
xtofl
3

Vielleicht so, vorausgesetzt, alle Methoden sind aufrufbar

app = App(root) # some object call app 
att = dir(app) #get attr of the object att  #['doc', 'init', 'module', 'button', 'hi_there', 'say_hi']

for i in att: 
    if callable(getattr(app, i)): 
        print 'callable:', i 
    else: 
        print 'not callable:', i
user6559980
quelle
1

Wenn sich Ihre Methode außerhalb einer Klasse befindet und Sie sie nicht ausführen und eine Ausnahme auslösen möchten, wenn sie nicht vorhanden ist:

'mymethod' in globals()

Gerowam
quelle
1
>>> def myadd (x, y): return x + y >>> 'myadd' in globals () True
gerowam
-1

Ich denke, Sie sollten sich das inspectPaket ansehen . Es ermöglicht Ihnen, einige der Dinge zu "verpacken". Wenn Sie die dirMethode verwenden, werden auch integrierte Methoden, geerbte Methoden und alle anderen Attribute aufgelistet, die Kollisionen ermöglichen, z.

class One(object):

    def f_one(self):
        return 'class one'

class Two(One):

    def f_two(self):
        return 'class two'

if __name__ == '__main__':
    print dir(Two)

Das Array Sie erhalten dir(Two)enthält sowohl f_oneund f_twound eine Menge in Sachen gebaut. Mit inspectkönnen Sie dies tun:

class One(object):

    def f_one(self):
        return 'class one'

class Two(One):

    def f_two(self):
        return 'class two'

if __name__ == '__main__':
    import inspect

    def testForFunc(func_name):
        ## Only list attributes that are methods
        for name, _ in inspect.getmembers(Two, inspect.ismethod):
            if name == func_name:
                return True
        return False

    print testForFunc('f_two')

In diesen Beispielen werden weiterhin beide Methoden in den beiden Klassen aufgelistet. Wenn Sie jedoch die Inspektion auf die Funktion nur in einer bestimmten Klasse beschränken möchten, ist etwas mehr Arbeit erforderlich, dies ist jedoch absolut möglich.

aweis
quelle