Importierte Funktion mit Namen in einem String starten

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
Auxilium
User
Beiträge: 2
Registriert: Dienstag 25. Dezember 2018, 12:47

Hallo,
ich programmiere momentan einen Discord Bot und habe ein paar Probleme mit meinem Command Handler.
Mein System sieht momentan so aus:

Code: Alles auswählen

        text = str(message.content)
        command = text.split(" ")[0]
        command = command.replace(command[:1], "")
        args = text.split(" ")
        args.pop(0)
Die Zuordnung funktioniert auch wunderbar. Nun muss ich nur noch die Entsprechende Funktion starten.
Meine Struktur besagt nun, dass es einen Ordner gibt, in dem alle Commands liegen.
Diese werden dann Importiert

Code: Alles auswählen

from commands import *
und müssen nun gestartet werden.
Das ist nun mein Problem, da der Funktionsname in dem String "command" ist.
Ich habe schon mal etwas geschaut und habe es so versucht:

Code: Alles auswählen

globals()[command](command, args, message, client)
leider ohne Erfolg.

Hat da jemand eine Idee? Für andere Vorschläge bezüglich der Struktur bin ich immer offen.
Ich möchte es jedoch vermeiden, mit einem Dictionary zu arbeiten, da ich früher schlechte und unübersichtliche Erfahrungen damit gemacht habe.
Grüße,
Auxilium

PS: Hier noch ein paar Daten zu meinem System: Python 3.6 (PyCharm) auf Windows 10 pro 64bit.
Sirius3
User
Beiträge: 17781
Registriert: Sonntag 21. Oktober 2012, 17:20

`message.content` ist hoffentlich schon ein String, diesen dann zweimal zu splitten, einmal für command und einmal für args ist umständlich. Wenn man das erste Zeichen nicht braucht, das mit replace zu machen, höchst wahrscheinlich sogar fehlerhaft. Warum soll denn da das erste Zeichen weg?
Und ja, die Lösung ist das verwenden von einem Wörterbuch, was auch immer Du da für Erfahrungen gemacht hast.

Bleibt also:

Code: Alles auswählen

from commands import COMMANDS
command, *args = message.content.split(" ")
command = command[1:]
COMMANDS[command](command, args, message, client)
Mit dem Wörterbuch im Modul `commands`:

Code: Alles auswählen

COMMANDS = {
    "bla": do_bla,
    "blub": do_blub,
    ...
}
nezzcarth
User
Beiträge: 1638
Registriert: Samstag 16. April 2011, 12:47

Auxilium hat geschrieben: Dienstag 25. Dezember 2018, 13:39 Ich möchte es jedoch vermeiden, mit einem Dictionary zu arbeiten, da ich früher schlechte und unübersichtliche Erfahrungen damit gemacht habe.
Da solltest du vielleicht dran arbeiten :), denn die eingebauten Datentypen sind m.M.n. eine der großen Stärken von Python. Abgesehen davon sind z.B. große Teile des Objektsystem von Python innerhalb der Sprache im Prinzip auf Dictionaries aufgebaut. Der souveräne Umgang mit den Datenstrukturen gehört meiner Meinung nach zu den Grundlagen, um die Sprache sinnvoll nutzen zu können.

Für deine Frage gibt es verschiedene Lösungen. Die unmittelbare -- aber eher unsaubere -- wäre, auf den Sternchen-Import zu verzichten und die Funktionen dann mit 'getattr' anzusprechen. Sauberer wäre es aber finde ich, die Funktionen intern auf irgendeine Weise zu registrieren und mit ihrem Befehl zu verknüpfen. Das kann am einfachsten z.B. über ein Dictionary erfolgen.

Ansonsten sieht deine Methode, den Befehl zu parsen etwas umständlich aus. Um das besser einschätzen zu können, müsste man aber mehr sehen.
Auxilium
User
Beiträge: 2
Registriert: Dienstag 25. Dezember 2018, 12:47

Sirius3 hat geschrieben: Dienstag 25. Dezember 2018, 16:22 `message.content` ist hoffentlich schon ein String, diesen dann zweimal zu splitten, einmal für command und einmal für args ist umständlich. Wenn man das erste Zeichen nicht braucht, das mit replace zu machen, höchst wahrscheinlich sogar fehlerhaft. Warum soll denn da das erste Zeichen weg?
Danke für deine Antwort. Message.content ist ein Datentyp vom Discord Modul ist aber mit str() in einen String umwandelbar. Das erste Zeichen soll weg, weil es der Prefix ist. (Ähnlich wie "Alexa, ...")
Ich möchte es so gestalten, dass ich die main Datei nicht mehr anfassen muss und alles automatisch abläuft...(so wie ein guter Parser auch sein sollte)
Deshalb auch die dargestellte Überlegung.

LG
Benutzeravatar
__blackjack__
User
Beiträge: 13167
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Auxilium: Nein, `message.content` ist bereits eine Zeichenkette, da braucht man nichts mehr umwandeln: https://discordpy.readthedocs.io/en/lat ... ge.content
“There will always be things we wish to say in our programs that in all known languages can only be said poorly.” — Alan J. Perlis
Antworten