Ich habe ein Script mit 4 Funktionen und 3 globale Variablen geschrieben. 2 Funktionen werden erstmal ausgeführt um was zu checken. Danach wird die eigentliche Funktion gestartet.
Jetzt stellt sich mir die Frage, ob ich alles in eine Klasse machen sollte oder einfach unterm Code die Funktionen nach und nach starten.
Meine Vorstellung wäre eine Klasse mit der Methode __init__ zu erstellen und dort alles was ausgeführt werden soll zu schreiben. Danach in der selbigen Datei die Klasse und nur deren __init__ starten.
Oder wie wäre der logischte Vorgang der Situation?
Ein Script mit einer Klasse starten
- __blackjack__
- User
- Beiträge: 13919
- Registriert: Samstag 2. Juni 2018, 10:21
- Wohnort: 127.0.0.1
- Kontaktdaten:
@egon11: Warum globale Variablen? Das sollte nicht sein.
Klassen ”startet” man nicht und die werden auch nicht ausgeführt. Wenn die `__init__()` durchgelaufen ist, und damit der Ablauf für dieses Objekt am Ende ist, dann ist das auch komisch bis falsch, denn die `__init__()` ist zum initialisieren des Objekts da. Danach sollte man ein Objekt haben was *dann* benutzt werden kann. Klassen beschreiben ein “Ding“ im weitesten Sinne, also ist die Frage ob das hier der Fall ist, oder nicht bloss Funktionen in die Klasse gesteckt wurden, die statt über globale Variablen über eigentlich nicht zusammengehörende Attribute kommunizieren.
Klassen ”startet” man nicht und die werden auch nicht ausgeführt. Wenn die `__init__()` durchgelaufen ist, und damit der Ablauf für dieses Objekt am Ende ist, dann ist das auch komisch bis falsch, denn die `__init__()` ist zum initialisieren des Objekts da. Danach sollte man ein Objekt haben was *dann* benutzt werden kann. Klassen beschreiben ein “Ding“ im weitesten Sinne, also ist die Frage ob das hier der Fall ist, oder nicht bloss Funktionen in die Klasse gesteckt wurden, die statt über globale Variablen über eigentlich nicht zusammengehörende Attribute kommunizieren.
“Java is a DSL to transform big Xml documents into long exception stack traces.”
— Scott Bellware
— Scott Bellware
- noisefloor
- User
- Beiträge: 4149
- Registriert: Mittwoch 17. Oktober 2007, 21:40
- Wohnort: WW
- Kontaktdaten:
Hallo,
Gruß, noisefloor
Die Frage ist zu pauschal gestellt, kann man so nicht antwortet. Da müsstest du schon konkreter werden. Aber wenn du eine Klasse nur instanzierst und danach nicht mehr brauchst, brauchst du ziemlich sicher keine Klasse. Bzw. der Sinn wäre verfehlt, siehe Erklärung von @__blackjack__.Oder wie wäre der logischte Vorgang der Situation?
Gruß, noisefloor
Also im Prinzip ist es ja so, dass ich ein Objekt Namens "USB einhängen" habe.
Als globale Variablen habe ich UUID, Pfad usw. diese Variable brauche ich in mehreren Funktionen.
Ich habe eine Funktion die Prüft ob das Medium schon eingehängt ist oder nicht, eine andere hängt sie dann ein.
In der Letzten Funktion wird, je nachdem was passiert das Medium wieder ausgehängt. Das alles mal so grob gesagt.
Aktuell habe ich es ohne Klasse geschrieben und anschließen die Funktionen nach und nach gestartet unter
Weil ich von Java her nur Klassen "kenne" wo das so gemacht wird, dachte ich mir das ist in Python auch so.
Es geht mir wie gesagt nicht um den Inhalt meines Anliegens, sondern um das Schema an sich.
Als globale Variablen habe ich UUID, Pfad usw. diese Variable brauche ich in mehreren Funktionen.
Ich habe eine Funktion die Prüft ob das Medium schon eingehängt ist oder nicht, eine andere hängt sie dann ein.
In der Letzten Funktion wird, je nachdem was passiert das Medium wieder ausgehängt. Das alles mal so grob gesagt.
Aktuell habe ich es ohne Klasse geschrieben und anschließen die Funktionen nach und nach gestartet unter
Code: Alles auswählen
if __name__ == "__main__":
Es geht mir wie gesagt nicht um den Inhalt meines Anliegens, sondern um das Schema an sich.
- noisefloor
- User
- Beiträge: 4149
- Registriert: Mittwoch 17. Oktober 2007, 21:40
- Wohnort: WW
- Kontaktdaten:
Hallo,
das hilft immer noch nicht wirklich...
Vielleicht solltest du mal den Code zeigen statt in Volltextprosa alles auf Meta-Ebene beschreiben zu wollen.
Gruß, noisefloor
das hilft immer noch nicht wirklich...
Da in Python alles ein Objekt ist, kann man daraus nichts ableiten. "USB einhängen" ist von der Namensgebung her eine Funktion, weil es eine Tätigkeit beschreibt.Also im Prinzip ist es ja so, dass ich ein Objekt Namens "USB einhängen" habe.
Na ja, Java ist nicht Python und Python nicht Java. In Java hast du ja bzgl. Klassen keine Wahl. Jedenfalls ist Entwurfsmuster 1:1 von Java auf Python übertragen i.d.R. ein Fehler.Weil ich von Java her nur Klassen "kenne" wo das so gemacht wird, dachte ich mir das ist in Python auch so.
Vielleicht solltest du mal den Code zeigen statt in Volltextprosa alles auf Meta-Ebene beschreiben zu wollen.
Gruß, noisefloor
@egon11: Und die Frage ist, ob du globale Variablen oder globale Konstanten hast. Also ob sich deren Werte irgendwann zur Laufzeit ändern (zum Beispiel beim "Einhängen"). Wenn die sich ändern, dann ist es falsch sie global zu haben. In jeder Programmiersprache, die Namensräume kennt.
Ok.
Code: Alles auswählen
#!/usr/bin/python3
from modul import modul_mount as modul
from pathlib import Path
import subprocess
import time
import evdev
import sys
folder = "usb"
tastencode = "79"
var = "/home/user/Scripte/tmp/" + folder + ".txt"
def dev_search_pad():
gib_pfad_zurueck = ""
if Path(var).exists():
with open (var, "r") as pfad:
ausgabe = pfad.read()
gib_pfad_zurueck = ausgabe
else:
print("exit")
sys.exit(0)
return gib_pfad_zurueck
def mount_drive():
while True:
if modul.check_mount(dev_search_pad()) == False:
print(dev_search_pad())
modul.einhaengen(dev_search_pad(), folder)
time.sleep(3)
if modul.check_mount(dev_search_pad()) == True:
command = ["play", "-n", "synth", "2", "sin", "1000"]
process = subprocess.Popen(command, stdout=None)
stdout, stderr = process.communicate()
break
def umount_drive():
zaehler = 0
command = ["play", "-n", "synth", "0.2", "sin", "3000"]
device = evdev.InputDevice('/dev/input/event3')
device.grab()
print("umount")
if modul.check_mount(dev_search_pad()) == True:
try:
for event in device.read_loop():
if event.type == evdev.ecodes.EV_KEY:
data = evdev.categorize(event)
if data.keystate == 1:
if str(data.scancode) == tastencode:
modul.aushaengen(folder)
time.sleep(3)
if modul.check_mount(dev_search_pad()) == False:
while zaehler < 3:
process = subprocess.Popen(command, stdout=None)
stdout, stderr = process.communicate()
zaehler += 1
device.close()
Path(var).unlink()
quit()
except KeyboardInterrupt:
print("abgebrochen")
if __name__ == "__main__":
mount_drive()
umount_drive()
- noisefloor
- User
- Beiträge: 4149
- Registriert: Mittwoch 17. Oktober 2007, 21:40
- Wohnort: WW
- Kontaktdaten:
Hallo,
ohne das ominöse Modul `modul` kann man das nicht abschließend beurteilen, ob man das auch sinnvoll anders machen könnten. Bei gezeigtem Code sehe ich keinen Sinn für eine Klasse.
Die Funktion `dev_search_pad` ist extrem schräg vom Verhalten: entweder liefert sie den Inhalt einer Textdatei zurück (und keinen Pfad, wie die Namen implizieren) oder beendet direkt das komplette Programm. Ziemlich inkonsistent.
Apropos inkonsistent: die Benennung ist ein wilder Mix aus deutsch und englisch. Warum benennst du denn Funktionen auf englisch, aber alle Variablen auf deutsch?
Du benutzt richtigerweise pathlib, aber stückelst bei `var` Pfade aus Strings zusammen. Das macht man dann auch konsequenter Weise mit `Path`. `var` ist ein viel zu generischer Name und außerdem gar nicht variable, sondern eine Konstante im gezeigten Code. `stdout, stderr = process.communicate()` : weder `stdout` noch `stderr` werden im gezeigten Code verwendet. Der gezeigte Code kann so gar nicht laufen, weil `quit` in `umount_drive()` nicht definiert ist.
Gruß, noisefloor
ohne das ominöse Modul `modul` kann man das nicht abschließend beurteilen, ob man das auch sinnvoll anders machen könnten. Bei gezeigtem Code sehe ich keinen Sinn für eine Klasse.
Die Funktion `dev_search_pad` ist extrem schräg vom Verhalten: entweder liefert sie den Inhalt einer Textdatei zurück (und keinen Pfad, wie die Namen implizieren) oder beendet direkt das komplette Programm. Ziemlich inkonsistent.
Apropos inkonsistent: die Benennung ist ein wilder Mix aus deutsch und englisch. Warum benennst du denn Funktionen auf englisch, aber alle Variablen auf deutsch?
Du benutzt richtigerweise pathlib, aber stückelst bei `var` Pfade aus Strings zusammen. Das macht man dann auch konsequenter Weise mit `Path`. `var` ist ein viel zu generischer Name und außerdem gar nicht variable, sondern eine Konstante im gezeigten Code. `stdout, stderr = process.communicate()` : weder `stdout` noch `stderr` werden im gezeigten Code verwendet. Der gezeigte Code kann so gar nicht laufen, weil `quit` in `umount_drive()` nicht definiert ist.
Gruß, noisefloor
Doch der Code läuft bei allen Ereignissen sauber durch. Ja die Variablennamen muss ich noch anpassen. Das Modul 'modul' beinhaltet Funktionen was den USB einhängt, aushängt und checkt ob dieser schon eingehängt ist.
Das man bei 'Path' auch Strings zusammenfügen kann wusste ich nicht.
'dev_search_pad' macht schon Sinn, weil wenn diese Datei nicht vorhanden ist, dann MUSS das Script beendet werden, denn dann macht alles andere keinen Sinn.
'stdout, stderr = process.communicate()' muss unbedingt vorhanden sein, sonst gibt es keinen Ton aus.
Das man bei 'Path' auch Strings zusammenfügen kann wusste ich nicht.
'dev_search_pad' macht schon Sinn, weil wenn diese Datei nicht vorhanden ist, dann MUSS das Script beendet werden, denn dann macht alles andere keinen Sinn.
'stdout, stderr = process.communicate()' muss unbedingt vorhanden sein, sonst gibt es keinen Ton aus.
- noisefloor
- User
- Beiträge: 4149
- Registriert: Mittwoch 17. Oktober 2007, 21:40
- Wohnort: WW
- Kontaktdaten:
Hallo,
Zur Ausgangsfrage noch: im gezeigten Code werden keine Werte wie UUID etc. an mehreren Stellen verwendet. Von daher macht deine Ausgangsfrage bei dem gezeigten Code keinen Sinn.
Gruß, noisefloor
Wie gesagt: `quit()` ist nicht definiert, an der Stelle kommt ein NameError. Sofern du hier deinen realen Code zeigst und nicht Teile vorenthältst.Doch der Code läuft bei allen Ereignissen sauber durch.
Ich habe auch nicht gesagt, dass das keinen Sinn macht, sondern dass das extrem schräge implementiert ist und der Rückgabewert bzw. das Verhalten der Funktion extrem inkonsistent ist. Wenn die Datei nicht vorhanden ist, dann sollte die Funktion z.B. `False` zurück liefern, damit du das an passender Stelle behandeln kannst. Außerdem prüft die Funktion nicht nur, ob die Datei vorhanden ist, sondern liefern auch deren Inhalt zurück. Das sind zwei Funktionalitäten in einer Funktion, sollte man ggf. trennen.'dev_search_pad' macht schon Sinn, weil wenn diese Datei nicht vorhanden ist, dann MUSS das Script beendet werden, denn dann macht alles andere keinen Sinn.
Warum benutzt du überhaupt `subprocess.Popen()` statt `subprocess.run()`? Du hast ja scheinbar keine Notwendigkeit, mit dem laufenden Prozess zu interagieren.'stdout, stderr = process.communicate()' muss unbedingt vorhanden sein, sonst gibt es keinen Ton aus.
Zur Ausgangsfrage noch: im gezeigten Code werden keine Werte wie UUID etc. an mehreren Stellen verwendet. Von daher macht deine Ausgangsfrage bei dem gezeigten Code keinen Sinn.
Gruß, noisefloor
Ok dann mache ich es mit '`subprocess.run()', mal schauen ob es dann funktioniert.
Wie fügt man unter Pathlib mehrere Pfade zusammen?
Ich dachte man kann im Vorfeld ein String zurecht machen und dann später den Pathlib übergeben.
Ja ich hatte erst die Variable 'UUID' erst mit drin gehabt, aber nachdem ich es nochmal überarbeitet hatte habe ich es anders gemacht.
Wie fügt man unter Pathlib mehrere Pfade zusammen?
Ich dachte man kann im Vorfeld ein String zurecht machen und dann später den Pathlib übergeben.
Ja ich hatte erst die Variable 'UUID' erst mit drin gehabt, aber nachdem ich es nochmal überarbeitet hatte habe ich es anders gemacht.
- noisefloor
- User
- Beiträge: 4149
- Registriert: Mittwoch 17. Oktober 2007, 21:40
- Wohnort: WW
- Kontaktdaten:
Hallo,
Gruß, noisefloor
Link zur Doku, Abschnitt "Basic Use", 3. Beispiel.Wie fügt man unter Pathlib mehrere Pfade zusammen?
Gruß, noisefloor
@egon: ein Paket modul zu nennen ist sehr verwirrend. Zumal es dann innerhalb dieses Pakets noch ein Modul `modul_mount` gibt, das Du dann aber mit dem Namen `modul` importierst.
Namen sollten immer aussagekräftig sein, ein Modul mit dem Zusatz modul zu benennen, trägt nichts dazu bei, also warum nicht einfach das Modul `mount` nennen, und das Paket so, wie Dein Projekt heißt, denn da sollte ja alles rein, was zum aktuellen Projekt gehört.
Konstanten werden generell komplett GROSS geschrieben.
Die Funktion `dev_search_pad` schrumpft zu einer Zeile zusammen:
denn die Fehlerbehandlung sollte über Exceptions laufen und außerhalb der Funktion stattfinden.
In `mount_drive` wird vier mal `dev_search_pad` aufgerufen, wobei das einmal am Anfang reichen würde. Man prüft nicht explizit auf True oder False.
umount_drive macht deutlich mehr, als nur etwas zu entmounten. Das sollten also mehrere Funktionen sein.
Warum wandelst Du eine Zahl in einen String um, um dann diesen String mit einer als String geschriebenen Zahl zu vergleichen?
Man initialisiert keine Variable sieben Blöcke oberhalb und 14 Zeilen bevor man sie braucht. Statt der while-Schleife mit zaehler wäre eine for-Schleife besser.
Das ganze könnte also so aussehen:
Namen sollten immer aussagekräftig sein, ein Modul mit dem Zusatz modul zu benennen, trägt nichts dazu bei, also warum nicht einfach das Modul `mount` nennen, und das Paket so, wie Dein Projekt heißt, denn da sollte ja alles rein, was zum aktuellen Projekt gehört.
Konstanten werden generell komplett GROSS geschrieben.
Die Funktion `dev_search_pad` schrumpft zu einer Zeile zusammen:
Code: Alles auswählen
Path(var).read_text()
In `mount_drive` wird vier mal `dev_search_pad` aufgerufen, wobei das einmal am Anfang reichen würde. Man prüft nicht explizit auf True oder False.
umount_drive macht deutlich mehr, als nur etwas zu entmounten. Das sollten also mehrere Funktionen sein.
Warum wandelst Du eine Zahl in einen String um, um dann diesen String mit einer als String geschriebenen Zahl zu vergleichen?
Man initialisiert keine Variable sieben Blöcke oberhalb und 14 Zeilen bevor man sie braucht. Statt der while-Schleife mit zaehler wäre eine for-Schleife besser.
Das ganze könnte also so aussehen:
Code: Alles auswählen
#!/usr/bin/python3
import mount
from pathlib import Path
import subprocess
import time
import evdev
FOLDER = "usb"
UNMOUNT_KEY_CODE = 79
CONFIG_PATH = Path("/home/user/Scripte/tmp/")
def play_sound(duration, frequency):
command = ["play", "-n", "synth", str(duration), "sin", str(frequency)]
subprocess.run(command)
def read_mount_path(folder):
path = CONFIG_PATH / f"{folder}.txt"
return path.read_text()
def mount_drive(folder):
mount_path = read_mount_path(folder)
while not mount.check_mount(mount_path):
print(mount_path)
mount.einhaengen(mount_path, folder)
time.sleep(3)
play_sound(2, 1000)
return mount_path
def wait_for_key(scancode):
device = evdev.InputDevice("/dev/input/event3")
try:
device.grab()
for event in device.read_loop():
if event.type == evdev.ecodes.EV_KEY:
data = evdev.categorize(event)
if data.keystate == 1 and data.scancode == scancode:
return True
except KeyboardInterrupt:
print("abgebrochen")
finally:
device.close()
return False
def umount_drive(mount_path, folder):
mount.aushaengen(folder)
time.sleep(3)
if not mount.check_mount(mount_path):
for _ in range(3):
play_sound(0.2, 3000)
def main():
mount_path = mount_drive(FOLDER)
if mount.check_mount(mount_path):
if wait_for_key(UNMOUNT_KEY_CODE):
umount_drive(mount_path)
if __name__ == "__main__":
main()