2396 Stimmen

Aufruf einer Funktion eines Moduls mit Hilfe seines Namens (einer Zeichenkette)

Was ist der beste Weg, um eine Funktion aufzurufen, wenn man eine Zeichenkette mit dem Namen der Funktion in einem Python-Programm hat. Nehmen wir zum Beispiel an, dass ich ein Modul habe foo und ich habe eine Zeichenkette mit folgendem Inhalt "bar" . Wie kann ich am besten anrufen? foo.bar() ?

Ich muss den Rückgabewert der Funktion erhalten, weshalb ich nicht einfach eval . Ich habe herausgefunden, wie man das macht, indem man eval um eine temporäre Funktion zu definieren, die das Ergebnis dieses Funktionsaufrufs zurückgibt, aber ich hoffe, dass es einen eleganteren Weg gibt, dies zu tun.

8 Stimmen

Die Verwendung von eval würde wahrscheinlich einige Sicherheitsbedenken aufwerfen!

23 Stimmen

Zu Ihrer Information: Das Sprachmerkmal des Zugriffs auf Felder, Klassen und Methoden durch dynamische Namen heißt Reflexion . Das könnte die künftige Suche erleichtern.

18voto

Natdrip Punkte 1040

Nichts von dem, was vorgeschlagen wurde, hat mir geholfen. Ich habe jedoch Folgendes entdeckt.

<object>.__getattribute__(<string name>)(<params>)

Ich verwende Python 2.66

Ich hoffe, das hilft

23 Stimmen

Inwiefern ist dies besser als getattr()?

1 Stimmen

Genau das, was ich wollte. Funktioniert wie ein Zauber! Perfekt!! self.__getattribute__('title') ist gleich self.title

0 Stimmen

self.__getattribute__('title') funktioniert in keinem Fall (ich weiß nicht warum), aber func = getattr(self, 'title'); func(); tut. Vielleicht ist es also besser, die getattr() stattdessen

17voto

Lukas Punkte 1637

Obwohl getattr() eine elegante (und etwa 7x schnellere) Methode ist, können Sie den Rückgabewert der Funktion (lokal, Klassenmethode, Modul) mit eval so elegant wie x = eval('foo.bar')() . Und wenn man eine Fehlerbehandlung implementiert, dann ziemlich sicher (das gleiche Prinzip kann für getattr verwendet werden). Beispiel mit Modulimport und Klasse:

# import module, call module function, pass parameters and print retured value with eval():
import random
bar = 'random.randint'
randint = eval(bar)(0,100)
print(randint) # will print random int from <0;100)

# also class method returning (or not) value(s) can be used with eval: 
class Say:
    def say(something='nothing'):
        return something

bar = 'Say.say'
print(eval(bar)('nice to meet you too')) # will print 'nice to meet you' 

Wenn ein Modul oder eine Klasse nicht existiert (Tippfehler oder ähnliches), wird ein NameError ausgelöst. Wenn eine Funktion nicht existiert, wird ein AttributeError ausgelöst. Dies kann verwendet werden, um Fehler zu behandeln:

# try/except block can be used to catch both errors
try:
    eval('Say.talk')() # raises AttributeError because function does not exist
    eval('Says.say')() # raises NameError because the class does not exist
    # or the same with getattr:
    getattr(Say, 'talk')() # raises AttributeError
    getattr(Says, 'say')() # raises NameError
except AttributeError:
    # do domething or just...
    print('Function does not exist')
except NameError:
    # do domething or just...
    print('Module does not exist')

17voto

Aliakbar Ahmadi Punkte 306

In Python3 können Sie die __getattribute__ Methode. Siehe folgendes Beispiel mit einer Liste von Methodennamen:

func_name = 'reverse'

l = [1, 2, 3, 4]
print(l)
>> [1, 2, 3, 4]

l.__getattribute__(func_name)()
print(l)
>> [4, 3, 2, 1]

2 Stimmen

Dies ist ein Duplikat von diese Antwort und ist aus denselben Gründen auch nicht die beste Praxis: Verwenden Sie einfach getattr(obj, attr) stattdessen.

11voto

U12-Forward Punkte 64772

Niemand erwähnt operator.attrgetter noch nicht:

>>> from operator import attrgetter
>>> l = [1, 2, 3]
>>> attrgetter('reverse')(l)()
>>> l
[3, 2, 1]
>>>

8voto

정도유 Punkte 519

getattr ruft eine Methode nach Namen von einem Objekt aus auf. Dieses Objekt sollte jedoch die Elternklasse der aufrufenden Klasse sein. Die übergeordnete Klasse kann man ermitteln durch super(self.__class__, self)

class Base:
    def call_base(func):
        """This does not work"""
        def new_func(self, *args, **kwargs):
            name = func.__name__
            getattr(super(self.__class__, self), name)(*args, **kwargs)
        return new_func

    def f(self, *args):
        print(f"BASE method invoked.")

    def g(self, *args):
        print(f"BASE method invoked.")

class Inherit(Base):
    @Base.call_base
    def f(self, *args):
        """function body will be ignored by the decorator."""
        pass

    @Base.call_base
    def g(self, *args):
        """function body will be ignored by the decorator."""
        pass

Inherit().f() # The goal is to print "BASE method invoked."

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