Plugin-basiertes Programm

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.
Benutzeravatar
YAPD
User
Beiträge: 120
Registriert: Dienstag 27. Juli 2021, 23:23
Wohnort: Frankfurt am Main

BITTE LÖSCHEN
Zuletzt geändert von YAPD am Mittwoch 28. Juli 2021, 22:15, insgesamt 1-mal geändert.
-----
Yet Another Python Developer
Benutzeravatar
YAPD
User
Beiträge: 120
Registriert: Dienstag 27. Juli 2021, 23:23
Wohnort: Frankfurt am Main

Eingerückt wird immer mit 4 Leerzeichen pro Ebene, weil das alle machen, und man sonst nicht Deinen Code in anderen Kopieren kann, ohne dass man alle Einrückungen anpassen muß.
Das habe ich immer gemacht !
`OM.Builder( Self, ...)` schreibt man nicht, weil Methoden immer über die Instanz referenziert werden: `Self.Builder(...)`.
Man benutzt keine globalen Variablen, auch wenn sie sich in einer Klassendefinition verstecken.
Diese 2. Punkte werde ich ändern. Dankeschön.
`Load` liefert einmal implizit None zurück und einmal explizit OBJ, das sollte nicht sein, in dem Fall gibt man explizit None zurück, oder aber man löst gleich eine Exception aus, weil man im Fall None nicht sinnvoll weiterarbeiten kann.
Ich schreibe gerade noch daran und es war für mich in diesem Status OK, dass er None ausgibt.
Ein ordentliches Error Handling entwerfe ich gerade, also Log - Handler usw.
Warum nennst Du in `Builder` `Module` in `OM_Package` um, warum nennst `Module` dann auch noch in `OM_FH` um, und in `OM_Class`? Wenn Du mit einer Variable arbeitest, mußt Du sie nicht erst gleich dem Ergebnis, das Du zum Schluß haben willst, umbenennen.
Das mit dem OM vorne habe ich geschrieben, weil es Objekte des Object Managers sind.
Kann man auch anders machen, aber das ist glaube ich unerheblich.

Ich verändere sowohl OM_FH als auch OM_Class während des Prozesses.
Da ich die Variable 'Module' aber später verwende :

OM.OM_Objects.update( { Module : OM_OBJ } )

kann ich sie nicht verändern, sondern muss Kopien erstellen.
Pfade sind keine Strings, man stückelt sie nicht mit + zusammen, und benutzt auch keinen hart codierten \ als Pfadtrenner. Statt dessen benutzt man pathlib.Path. Das ist platformunabhängig und nicht so fehleranfällig.
Ja, das habe ich bereits hier im Forum gelesen, bin aber noch nicht dazu gekommen, es zu ändern.
Auf False prüft man nicht explizit per == sondern per not. Auch hier löst man eine Exception aus, statt implizit None zurückzuliefern.
Flüchtigkeitsfehler. Danke.
Warum zählst Du, wie viele "::" vorkommen, um das dann mit split zu verwenden? split splittet ohne zweiten Parameter immer an allen Vorkommen.
Wie gesagt, ermittle ich damit den Namen. Da das Modul theoretisch
auch "Test::Kernel::Config::Testumgebung::Neu" sein kann, zähle ich
sie ab. Ich glaube nicht, dass split immer nur das letzte nimmt, muss
ich nochmal testen.
Um ein Element einem Wörterbuch hinzuzufügen benutzt man nicht update.
Wie gesagt, bin ich relativ neu in der Materie und ich habe in irgendeiner
Anleitung gelesen, dass man es mit update( ) macht. Sorry, wenn das
eine Fehleinschätzung war.

Gruß
YAPD
-----
Yet Another Python Developer
Benutzeravatar
YAPD
User
Beiträge: 120
Registriert: Dienstag 27. Juli 2021, 23:23
Wohnort: Frankfurt am Main

__blackjack__ hat geschrieben: Mittwoch 28. Juli 2021, 21:11 @YAPD: Beim Einrücken der Argumente bis zur öffnenden Klammer spricht dagegen, was alles umformatiert werden muss, wenn sich beispielsweise die Länge des Funktionsnamens ändert. Das sind dann alles Änderungen im Diff/der Versionsverwaltung die nur kosmetisch sind, und es schwerer machen die *eigentliche* Änderung zu erkennen.

Und ja es sind nur Richtlinien. Aber eben auch wieder nicht, weil Du da jedes mal drauf hingewiesen wirst, und viele verbreitete Projekte mittlerweile ein Tool zur Formatierung verwenden das fast gar keine Einstellungsmöglichkeiten hat. Da sieht das dann so aus wenn es nicht mehr in eine Zeile passt, die Argumente selbst aber immer noch auf eine Zeile passen:

Code: Alles auswählen

    
    result = some_function_that_takes_arguments(
        "a", "b", "c", "d", "e", "f", "g"
    )
Die `builder()`-Methode hätte ich `build()` genannt, denn Funktionen und Methoden werden üblicherweise nach der Tätigkeit benannt, die sie durchführen um sie von eher passiven Werten unterscheiden zu können. `builder` wäre ein passender Name für ein komplexeres `Builder`-Objekt.
Danke für deinen Beitrag, blackjack. :) Ich bin gerade etwas geknickt, hab den Code komplett alleine
geschrieben, bis auf kleine Ausnahmen und hab mich echt gefreut, dass alles so funktioniert. Außerdem
habe ich mir super Mühe gegeben, alles verständlich zu erklären für den Beitragsersteller. Der übrigens
seitdem nicht mehr geschrieben hat. :) Aber auf eines kann man wetten. Egal, wie gut dein Code ist oder
auch nicht, es wird immer einen Oberlehrer geben, der einem zeigt, wie schlecht man ist.

Gruß
YAPD
-----
Yet Another Python Developer
Sirius3
User
Beiträge: 17711
Registriert: Sonntag 21. Oktober 2012, 17:20

Jeder fängt mal mit etwas an, und sollte sich freuen, dazuzulernen.
YAPD hat geschrieben: Mittwoch 28. Juli 2021, 22:06 Das habe ich immer gemacht !
Offensichtlich kann ich bis 3 zählen.
YAPD hat geschrieben: Mittwoch 28. Juli 2021, 22:06 Das mit dem OM vorne habe ich geschrieben, weil es Objekte des Object Managers sind.
Kann man auch anders machen, aber das ist glaube ich unerheblich.
Das sind keine Objekte sondern alles lokale Variablen. Und bei lokalen Variablen ist es klar, dass sie zu einer Methode gehören, die in der Klasse OM definiert ist. Das OM_ sind also drei Buchstaben, die keinen Mehrwert bieten, sondern nur das Lesen behindern.
YAPD hat geschrieben: Mittwoch 28. Juli 2021, 22:06 Ich verändere sowohl OM_FH als auch OM_Class während des Prozesses.
Du hast eine falsche Vorstellung davon, was Variablen in Python sind; das sind nur Referenzen auf Objekte. Wenn man eine Referenz einer anderen Variable zuweist, werden keine Kopien erzeugt.
Strings sind unveränderlich, die können also gar nicht verändert werden.
narpfel
User
Beiträge: 643
Registriert: Freitag 20. Oktober 2017, 16:10

YAPD hat geschrieben: Mittwoch 28. Juli 2021, 22:13 und hab mich echt gefreut, dass alles so funktioniert.
Benutze einen Autoformatter wie `black`, dann kannst du dich zusätzlich noch freuen, dass dein Code immer gleich (gut?) aussieht. Und wir freuen uns, dass wir ihn lesen können. :-)

Und zum `dict.update`: Das wird leider in vielen Tutorials so gezeigt, und man kann als Anfänger natürlich nicht einschätzen, ob man da gerade guten Stil vermittelt bekommt. Schön wäre es mit `objects[module] = obj` (wobei man da potentiell auch noch die Namen verbessern könnte).
Benutzeravatar
YAPD
User
Beiträge: 120
Registriert: Dienstag 27. Juli 2021, 23:23
Wohnort: Frankfurt am Main

narpfel hat geschrieben: Donnerstag 29. Juli 2021, 00:18
YAPD hat geschrieben: Mittwoch 28. Juli 2021, 22:13 und hab mich echt gefreut, dass alles so funktioniert.
Benutze einen Autoformatter wie `black`, dann kannst du dich zusätzlich noch freuen, dass dein Code immer gleich (gut?) aussieht. Und wir freuen uns, dass wir ihn lesen können. :-)

Und zum `dict.update`: Das wird leider in vielen Tutorials so gezeigt, und man kann als Anfänger natürlich nicht einschätzen, ob man da gerade guten Stil vermittelt bekommt. Schön wäre es mit `objects[module] = obj` (wobei man da potentiell auch noch die Namen verbessern könnte).
Hi Narpfel,

bin heute nachtaktiv :)

Danke für deine Antwort. Ich werd zukünftig den Autoformatter ( halb - gezwungenermaßen :D ) verwenden.
Aber noch wichtiger zum Dictionary :

Ich hatte es vorher genau so. Wenn ich anschließend das Dic abgefragt habe, war immer nur 1 Eintrag
des letzten Loads vorhanden. Nachdem ich es auf update umgestellt habe, hat er beide ins Dic gepackt.
Ich dachte also, dass ich mit x["Test"] = "Test" das Dic überschreibe, während die update Funktion den
neuen Wert hinzufügt. Aber da war ein anderer Fehler dahinter, den ich schon beseitigt habe :) Wäre auch
seltsam, ich kenne das auch genauso von Perl.

Beste Grüße
YAPD
-----
Yet Another Python Developer
Benutzeravatar
YAPD
User
Beiträge: 120
Registriert: Dienstag 27. Juli 2021, 23:23
Wohnort: Frankfurt am Main

Jeder fängt mal mit etwas an, und sollte sich freuen, dazuzulernen.
Hab ja immer geschrieben, ich bin lernfähig :D
Offensichtlich kann ich bis 3 zählen.
OK, du hast Recht, bei den Subs hab ich irgendwie nur 3 gemacht, daher
verschiebt es sich über all um 1. Aber sonst sind es 4. Bei den defs,
ifs usw.
Das sind keine Objekte sondern alles lokale Variablen. Und bei lokalen Variablen
ist es klar, dass sie zu einer Methode gehören, die in der Klasse OM definiert ist.
Das OM_ sind also drei Buchstaben, die keinen Mehrwert bieten, sondern nur
das Lesen behindern.
Ich verstehe, was du meinst, letztendlich ist es aber Geschmackssache.
Du hast eine falsche Vorstellung davon, was Variablen in Python sind; das sind nur Referenzen
auf Objekte. Wenn man eine Referenz einer anderen Variable zuweist, werden keine Kopien erzeugt.
Strings sind unveränderlich, die können also gar nicht verändert werden.
Sorry, sei nicht böse, aber das verstehe ich nicht. Kannst du das ein bisschen erläutern. Ich weiß von
Perl, was Variablen sind und denke nicht, dass ich das falsch verstanden habe. Wenn ich einem String
x den Wert "Test" zuweise und danach den Wert "Neu" , ist der Wert, wenn ich ihn abfrage "Neu". Was
meinst du mit "Strings sind unveränderlich" ?

Beste Grüße
YAPD
-----
Yet Another Python Developer
Sirius3
User
Beiträge: 17711
Registriert: Sonntag 21. Oktober 2012, 17:20

Bei Perl hast Du doch das genau gleiche Verhalten:

Code: Alles auswählen

$x = "Test";
$y = $x;
$x = "Neu";
print $y;
$y zeigt weiterhin auf den String "Test". Dass $x danach auf einen neuen String "Neu" zeigt, ändert weder die Referenz auf $y noch den Inhalt des Objekts "Test".
Und auch wenn Du Strings verbindest, erzeugst Du damit nur ein neues Stringobjekt, und änderst das alte nicht:

Code: Alles auswählen

$x = "Test";
$y = $x;
$x .= "Neu";
print "$x / $y\n";
Benutzeravatar
kbr
User
Beiträge: 1487
Registriert: Mittwoch 15. Oktober 2008, 09:27

@Rango: hier noch eine Variante in mehr oder weniger lesbarer Form. Aufgegriffen habe ich die Idee eines direkten Unterverzeichnisses (hier "application_plugins"). Es werden nur Plugins geladen, die mit ".py" enden und nicht mit einem Unterstrich beginnen; so lassen sich Plugins im Verzeichnis auch wieder deaktivieren, ohne sie verschieben oder löschen zu müssen. Der Rückgabewert ist ein Mapping von URL auf ein callable:

Code: Alles auswählen

import importlib
import pathlib

def load_plugins(path="application_plugins"):
    path = pathlib.Path(path)
    return {
        imp.return_accepted_urls(): imp.scrape_url for imp in map(
            lambda entry: importlib.import_module(f"{path}.{entry}"), filter(
                lambda x: not x.startswith("_"), [entry.stem for entry in path.glob("*.py")]
            )
        )
    }
Benutzeravatar
__blackjack__
User
Beiträge: 13004
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

Da ist `map()`, `filter()`, und eine List-Comprehension was man zusammenfassen und als Generatorausdruck schreiben kann:

Code: Alles auswählen

def load_plugins(path="application_plugins"):
    path = pathlib.Path(path)
    return {
        module.return_accepted_urls(): module.scrape_url
        for module in (
            importlib.import_module(f"{path}.{module_path.stem}")
            for module_path in path.glob("*.py")
            if not module_path.name.startswith("_")
        )
    }
“Most people find the concept of programming obvious, but the doing impossible.” — Alan J. Perlis
Benutzeravatar
kbr
User
Beiträge: 1487
Registriert: Mittwoch 15. Oktober 2008, 09:27

Ja, im Grunde lässt sich auf map() und filter() durch LCs /GAs verzichten. Ist zumeist auch eleganter.
Antworten