Funktionsnamen aus Variablen zusammensetzen

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
Trial&Error
User
Beiträge: 8
Registriert: Freitag 24. Juni 2016, 09:21

Hallo in die Runde,
ich bin mir sicher, dass sich das Problem mit dem richtigen Suchbegriff schnell lösen ließe aber ich komme einfach nicht darauf :(

Folgendes Problem:
Ich suche eine Möglichkeit die Namen von Funktionen dynamisch aus Variablen zu generieren.

Da ich die benötigten Informationen für jedes "Paket" aus verschienenen Quellen zusammenkratzen muss, habe ich mich dafür entschieden die einzelnen "Pakete" in Module (heißt das so?) auszugliedern. Wenn ich diese direkt anspreche (z.B.: rocketchat.getOPSI_PackageName()) funktioniert das auch. Aber bei später über 100 Modulen würde das in einem Spagetticode enden. Die Schleife war easy aber wie setze ich jetzt die Funktionsaufrufe aus den Variablen zusammen?

Irgend wo habe ich glesen, dass das mit "globals()" gehen soll. Das Endet bei mir aber einem "KeyError: rocketchat.getOPSI_PackageName()":

Code: Alles auswählen

import driver.rocketchat as rocketchat
import driver.powerfolder as powerfolder
…

pakete = {'rocketchat', 'powerfolder', 'openboard', '…'}

for paket in pakete:
    # Paketname ermitteln
    tmp = globals()[paket + '.getOPSI_PackageName']
    tmp()
    …
Ach so, ich scripte jetzt erst wieder seit 2 Tagen mit Python. Wenn jemand nen Tipp für ne einfachere Lösung als meine hat, bin ich auch nicht abgeneigt. :)

Ich freue mich auf eure Antworten.

MfG
Trial&Error
Benutzeravatar
snafu
User
Beiträge: 6740
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Denke dass hier __import__ am sinnigsten ist. So kommt man z.B. an os.chdir:

Code: Alles auswählen

module = __import__('os')
function = getattr(module, 'chdir')
Bleibt aber die Frage, ob das wirklich nötig ist. Die Namen von Paketen und Funktionen musst du doch trotzdem irgendwo hinschreiben. Warum dann nicht gleich "normal" importieren? Wo siehst du den Vorteil?
Trial&Error
User
Beiträge: 8
Registriert: Freitag 24. Juni 2016, 09:21

Ich bin mir gerade nicht sicher, ob ich das richtig verstehe, aber den import der Module habe ich eignetlich noch gar nicht in eine Schleife gebaut. Gegenwärtig importiere ich die einfach der Reihe nach:

Code: Alles auswählen

import driver.rocketchat as rocketchat
import driver.powerfolder as powerfolder
…
Mir geht es um den eigentlichen Funktionsaufruf innerhalb des main scriptes:

Code: Alles auswählen

rocketchat.getOPSI_PackageName()
powerfolder.getOPSI_PackageName()
openboard.getOPSI_PackageName()
putty.getOPSI_PackageName()
…
ich würde gerne folgendes in eine Schleife bauen:

Code: Alles auswählen

pakete = {'rocketchat', 'powerfolder', 'openboard', '…'}

for <Variable> in pakete:
    <Variable>.getOPSI_PackageName()
Ich habe bisher nicht herausgefunden, wie ich "<Variable>.getOPSI_PackageName()" in Python umsetzen kann.
Trial&Error
User
Beiträge: 8
Registriert: Freitag 24. Juni 2016, 09:21

ok, ich habe jetzt herausgefunden, wie ich es als String zusammensetzen lassen kann.

Code: Alles auswählen

tmp = '%s.getOPSI_PackageName' % (paket)
print(tmp)
Das Ergebnis passt: "rocketchat.getOPSI_PackageName"

Allerdings kann man Strings anscheinend nicht als Funktion ausführen

Code: Alles auswählen

tmp = '%s.getOPSI_PackageName' % (paket)
print(tmp())
Ergebnis:

Code: Alles auswählen

Traceback (most recent call last):
  File "./main.py", line 25, in <module>
    print(tmp())
TypeError: 'str' object is not callable
Benutzeravatar
snafu
User
Beiträge: 6740
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Dann eben so:

Code: Alles auswählen

modules = [rocketchat, powerfolder, openboard, putty]
for module in modules:
    pkg_name = getattr(module, 'getOPSI_PackageName')()
    print('Package name:', pkg_name)
Dein Ansatz, dass Strings magisch zum passenden Objekt werden, wenn man versucht sie aufzurufen, geht leider nicht auf. ;)
Benutzeravatar
pillmuncher
User
Beiträge: 1484
Registriert: Samstag 21. März 2009, 22:59
Wohnort: Pfaffenwinkel

Und das hier geht nicht?

Code: Alles auswählen

modules = [rocketchat, powerfolder, openboard, putty]
for module in modules:
    pkg_name = module.getOPSI_PackageName()
    print('Package name:', pkg_name)
In specifications, Murphy's Law supersedes Ohm's.
Trial&Error
User
Beiträge: 8
Registriert: Freitag 24. Juni 2016, 09:21

Danke für die Antworten! Beides funktioniert.

Wenn ich das jetzt richtig verstehe, war mein Fehler die Bezeichner "rocketchat", ... in Häkchen zu setzen? Damit habe ich sie für Python als String gekennzeichnet? richtig?

Da ich gerade nicht wirklich verstehe, was dieses "getattr()()" tut, habe ich mich jetzt für den zweiten Vorschlag entschieden.
Benutzeravatar
snafu
User
Beiträge: 6740
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

pillmuncher hat geschrieben: Freitag 31. August 2018, 17:46 Und das hier geht nicht?

Code: Alles auswählen

modules = [rocketchat, powerfolder, openboard, putty]
for module in modules:
    pkg_name = module.getOPSI_PackageName()
    print('Package name:', pkg_name)
Nicht wenn man ein Brett vorm Kopf hatte. Dieser Ansatz ist natürlich zu bevorzugen.
Benutzeravatar
snafu
User
Beiträge: 6740
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Trial&Error hat geschrieben: Freitag 31. August 2018, 19:14 Da ich gerade nicht wirklich verstehe, was dieses "getattr()()" tut, habe ich mich jetzt für den zweiten Vorschlag entschieden.
Ein getattr(obj, name) macht das selbe wie ein obj.name und wird verwendet, wenn name erst zur Laufzeit bekannt ist. In diesem Fall ist es aber unnötig. Es ist sinnvoller, an der zweiten Lösung festzuhalten, so wie du es ja auch getan hast.
Antworten