def wird nicht richtig ausgeführt

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
HenrySchiller
User
Beiträge: 2
Registriert: Donnerstag 12. Juli 2018, 17:52

Moin,

bin neu hier und auch noch relativ neu in Python.
Folgendes:
Ich möchte eine kleine Authentifizierungsmethode schreiben, welche nachher eine Tür öffnen soll.
Nichts großes, nur etwas einfaches. Folgenden Code habe ich mir zurechtgebastelt:

Code: Alles auswählen

#!usr/bin/python3

#Bibliotheken importieren
from tkinter import *


#Definitionen
def door(event):
    if id.get() == "123456":
        if check == "closed":
            #id.delete(first=0,last=1000)
            print("Authentifizierung erfolreich")
            print("Tür geschlossen")
        
        elif check == "open":
            #id.delete(first=0,last=1000)
            print("Authentifizierung erfolreich")
            print("Tür offen")  
  
    else:
        id.delete(first=0,last=1000)
        print("Authentifizierung nicht erfolreich")

#Fenster, welches immer im Vordergrund gehalten wird
window = Tk()
window.title("GWS")
window.geometry("190x60")

#Layout des Fensters
Label(window, text="ID").grid(row=0)

id = Entry(window)
id.grid(row=0, column=1)
id.focus_set()  # Fokus auf das Entry-Feld setzen
id.bind("<Return>",door)

check = open("doorstatus.txt").read()

mainloop()

Das Skript macht folgendes:
Es wird eine Eingabemaske erstellt, in der ich eine IDeingeben kann.
Dann wird mittels der Variable "check" in der "doorstatus.txt" geprüft, in welchem Zustand die Tür ist (open oder closed).
Mittels Eingabe-Taste springt er dann zur Funktion.

Ist die ID richtig, sollte nun "check" verglichen werden und entsprechend des Wertes dann entweder das eine
oder das andere If ausgeführt werden. Hier scheitert es aber. Der Code verhält sich so, als wenn er auf die check Variable nicht zugreifen kann (Sprich, es passiert nichts,
keine Fehlermeldung, kein nichts).

Ist die Funktion so geschrieben:

Code: Alles auswählen

def door(event):
    if id.get() == "123456":
	print(check)  
    else:
        id.delete(first=0,last=1000)
        print("Authentifizierung nicht erfolreich")
Wird "check" korrekt aus der Datei ausgelesen. Also Zugriff auf die Variable besteht.
Und nun seid ihr dran.
Warum wird der If-Block nicht ausgeführt?

Edit: Plattform ist ein Raspberry Pi2 mit Raspbian Stretch
Sirius3
User
Beiträge: 17741
Registriert: Sonntag 21. Oktober 2012, 17:20

Schau mal, was exakt in `check` steht, z.B. per `print(repr(check))`.

Ist es Absicht, dass doorstatus.txt nur einmal bei Programmstart gelesen wird?
HenrySchiller
User
Beiträge: 2
Registriert: Donnerstag 12. Juli 2018, 17:52

Dort steht (aktuell) "closed\n".
Also kann ja "check" nie sein, wie es sein soll, aber warum hängt er dann ein "\n" dran?

Zu dem Aufruf: Nein, das ist noch aus Testgründen so. Wenn ich weiß, dass die Abfrage sauber funktioniert,
dann änder ich das dementsprechend, aber danke für den Hinweis :)

EDIT:
Himmel, Ar... udn Zwirn, da muss man erstmal drauf kommen :D
Mir ist in der doorstatus.txt ne Leerzeile reingerutscht. Daher hat Python auch die Leerzeile mit in den String übernommen.
Kein Wunder, dass das nicht funktioniert. Vielen dank, für die Wegweisung :)
Nach oben
Hofei
User
Beiträge: 14
Registriert: Freitag 6. Januar 2017, 20:15

"\n" ist in Unix für den Zeilenumbruch zuständig:
https://stackoverflow.com/questions/154 ... tween-them

Code: Alles auswählen

string_ = "closed\n"
string_neu = string_.strip()
string_
Out[6]: 'closed\n'
string_neu
Out[7]: 'closed'
So kannst du das \n sehr einfach entfernen.

EDIT:
So wie du deine Datei einließt, wird diese nach dem einlesen nicht geschlossen. Entweder du verwendest hierfür das with Statement, oder du schließt die Datei manuell mit der methode close()
Benutzeravatar
__blackjack__
User
Beiträge: 13079
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@HenrySchiller: Die 1000 als Ende der Eingabedaten mag zwar sicher scheinen, aber sie muss es nicht sein und die Zahl ist auch ziemlich willkürlich. Wenn Du das Entry von Anfang bis Ende löschen willst, dann gibt es dafür im `tkinter`-Modul die Konstante `END`. Also ``id_entry.delete(0, END)``. Ich schrob hier `id_entry`, weil `id` eine eingebaute Funktion ist, und man den Namen deshalb besser nicht an etwas anderes binden sollte.

Die Kommentare sind im Grunde fast alle sinnlos weil sie nur das offensichtliche was da im Code steht, noch mal wiederholen.

Sternchen-Importe sollte man vermeiden. `tkinter` wird üblicherweise als `tk` importiert: ``import tkinter as tk``. Dann hat man nur den Namen `tk` im eigenen Modul und nicht die ca. 190 Namen die man sich mit einem Sternchen-Import einfängt, und die zu Verwirrung und Namenskollisionen führen können.

Die Namen `door` und `check` sind nicht gut gewählt. Funktionen und Methoden werden üblicherweise nach der Tätigkeit benannt die sie ausführen, damit der Leser weiss was die Funktion/Methode tut. `door` ist keine Tätigkeit. Auf der anderen Seite wäre `check` eine Tätigkeit, aber es handelt sich nicht um eine Funktion sondern um den aktuellen Zustand der Tür, was aus dem Namen `check` nicht erkennbar ist.

Auf Modulebene sollte nur Code stehen der Konstanten, Funktionen, und Klassen definiert. Das Hauptprogramm steht üblicherweise in einer Funktion die `main()` heisst.

Wenn das der Fall ist, kann `door()` nicht mehr einfach so auf `check` und `id` zugreifen, was auch gut ist, denn um einzelne Funktionen nachvollziehen zu können, müssen die in sich geschlossene Einheiten sein, die alles was sie ausser Konstanten benötigen als Argument(e) übergeben bekommen und nicht irgendwie ”magisch” aus der Umgebung holen.

Man kommt bei GUI-Programmierung deshalb letztlich nicht ohne objektorientierte Programmierung aus bei GUIs die nicht-trivial sind. In einfachen Fällen kommt man noch mit `functools.partial()` und/oder ``lambda``-Ausdrücken aus.

Die Fenstergeometrie sollte man nicht von aussen Vorgeben, sondern das den Layoutmanager erledigen lassen.

Du testest explizit auf 'open' und 'closed', da gehört bei defensiver Programmierung noch ein ``else``-Zweig hin der mindestens eine Fehlermeldung ausgibt, wenn der Zustand weder 'open' noch 'closed' ist. Das hätte Dir beim suchen des Fehlers ja sogar schon geholfen.

Ungetesteter Zwischenstand:

Code: Alles auswählen

#!usr/bin/env python3
import tkinter as tk


def do_check_door(id_entry):
    if id_entry.get() == '123456':
        with open('doorstatus.txt') as state_file:
            state = state_file.read().strip()

        if state == 'closed':
            print('Authentifizierung erfolreich')
            print('Tür geschlossen')
        elif state == 'open':
            print('Authentifizierung erfolreich')
            print('Tür offen')
        else:
            print('Fehler: Unbekannter Türstatus {0!r}!'.format(state))
    else:
        id_entry.delete(0, tk.END)
        print('Authentifizierung nicht erfolreich')


def main():
    window = tk.Tk()
    window.title('GWS')

    tk.Label(window, text='ID').grid(row=0, column=0)

    id_entry = tk.Entry(window)
    id_entry.grid(row=0, column=1)
    id_entry.focus_set()
    id_entry.bind('<Return>', lambda _event: do_check_door(id_entry))

    window.mainloop()


if __name__ == '__main__':
    main()
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
Antworten