Prüfen der Internetverbindung

Stellt hier eure Projekte vor.
Internetseiten, Skripte, und alles andere bzgl. Python.
Antworten
S0S
User
Beiträge: 50
Registriert: Samstag 9. Februar 2013, 18:59

Hallo,

ich habe ein kleines Programm geschrieben, was - wenn es läuft - jede Minute die Internetverbindung prüft (anhand der Tatsache, ob google.de erreichbar ist) und das Ergebnis zusammenfassend in eine Datei schreibt. Mir ist klar, dass globale Variablen schlechter Stil sind, aber offensichtlich kann die after-Methode nicht mit Funktionen umgehen, die Parameter mitbekommen, daher habe ich keinen anderen Weg gefunden. Außerdem ist die Minutenausgabe am Ende, da die Überprüfung nur 1x pro Minute stattfindet, nicht exakt, wenn es zu häufigen Wechseln zwischen Internet und kein Internet kommt.

Inspririert wurde das ganze durch die recht instabile Verbindung hier im Wohnheim, wo mich eine solche Statistik an manchen Abenden tatsächlich interessiert.

Ich freue mich wie immer über Anregungen und Verbesserungsvorschläge.

Code: Alles auswählen

import Tkinter
import datetime
import urllib

def connected():     # prueft, ob Internetverbindung vorhanden (google.de erreichbar)
    try:
        urllib.urlopen("http://www.google.de")
    except IOError:
        return False
    else:
        return True

def check_inet_connection():    # prueft jede Minute die Internetverbindung, schreibt bei Aenderung Ergebnis in Datei und zaehlt Online- und Offline-Minuten
    if stop == 0:
        global inet
        global online
        global offline
        global label

        label.config(text = "Programm lauft...")
        
        with open("inetconnection.txt", "a") as datei:
            jetzt = datetime.datetime.now()
            inet_neu = connected()
            if inet_neu == True:
                if inet_neu != inet:
                    datei.write("{}:{}:{} - Internet da\n".format(str(jetzt.hour).rjust(2,"0"), str(jetzt.minute).rjust(2,"0"), str(jetzt.second).rjust(2,"0")))
                online = online + 1
            else:
                if inet_neu != inet:
                    datei.write("{}:{}:{} - Internet weg\n".format(str(jetzt.hour).rjust(2,"0"), str(jetzt.minute).rjust(2,"0"), str(jetzt.second).rjust(2,"0")))
                offline = offline + 1
            inet = inet_neu

        root.after(60000, check_inet_connection)

def ende():          # beendet die Schleife zur Pruefung der Interntverbindung, schreibt gesamte Online- und Offline-Zeit in Datei
    global stop
    global label
    stop = 1
    jetzt = datetime.datetime.now()
    with open("inetconnection.txt", "a") as datei:
        datei.write("{}:{}:{} - Ende\n".format(str(jetzt.hour).rjust(2,"0"), str(jetzt.minute).rjust(2,"0"), str(jetzt.second).rjust(2,"0")))
        datei.write("online: {} Minuten, offline: {} Minuten\n".format(online, offline))
    label.config(text = "Programm kann geschlossen werden")


stop = 0 
root = Tkinter.Tk()

def main():
    with open("inetconnection.txt", "a") as datei:  # schreibt Datum und Uhrzeit des Programmstarts in Datei, ausserdem, ob Internetverbindung vorhanden
        global inet
        global online
        global offline
        
        jetzt = datetime.datetime.now()
        datei.write("{}.{}.{}".format(jetzt.day, jetzt.month, jetzt.year) + "\n")
        inet = connected()
        if inet == True:
            datei.write("{}:{}:{} - Internet da\n".format(str(jetzt.hour).rjust(2,"0"), str(jetzt.minute).rjust(2,"0"), str(jetzt.second).rjust(2,"0")))
            online = 1
            offline = 0
        else:
            datei.write("{}:{}:{} - Internet weg\n".format(str(jetzt.hour).rjust(2,"0"), str(jetzt.minute).rjust(2,"0"), str(jetzt.second).rjust(2,"0")))
            online = 0
            offline = 1

    menu = Tkinter.Menu(root)      # Erstellen der GUI
    root.config(menu=menu)

    global label
    button = Tkinter.Button(text="Quit", command=ende)
    button2 = Tkinter.Button(text="Start", command=check_inet_connection)
    button2.pack()
    button.pack()
    label = Tkinter.Label(root, text="bitte auf Start klicken")
    label.pack()
    root.mainloop()

if __name__ == "__main__":
    main()
Zuletzt geändert von Anonymous am Montag 25. Juli 2016, 11:37, insgesamt 1-mal geändert.
Grund: Quelltext in Python-Codebox-Tags gesetzt.
BlackJack

@S0S: Verbesserungsvorschlag: Werd die globalen Variablen los. Und `after()` kann man auch Argumente für den verzögerten Funktionsaufruf mitgeben.
S0S
User
Beiträge: 50
Registriert: Samstag 9. Februar 2013, 18:59

Kannst du mal ein Beispiel zeigen, wie das mit den Argumenten und after funktioniert? Denn das habe ich eine ganze Weile versucht und mich gewundert, warum es nicht klappt, obwohl der einzige Unterschied zwischen dem, was ich geschrieben hatte, und dem, was ich im Internet gefunden hatte, war, dass die Funktion Argumente hatte. Daher habe ich es dann irgendwann aufgegeben.
S0S
User
Beiträge: 50
Registriert: Samstag 9. Februar 2013, 18:59

Also das hier funktioniert nicht:

Code: Alles auswählen

import Tkinter
import time
s = 0

def ende():
    global s
    s = 1
    print "stopped"

def callback(x):
    if s == 0:
        x=x+1
        root.after(3000, callback(x))

root = Tkinter.Tk()

def main():


    # create a menu
    menu = Tkinter.Menu(root)
    root.config(menu=menu)

    x = 0
    button = Tkinter.Button(text="Quit", command=ende)
    button2 = Tkinter.Button(text="Start", command=callback(x))
    button.pack()
    button2.pack()
    root.mainloop()

    time.sleep(3)

main()
Das ist der Beispielcode, den ich im Internet gefunden habe. Ich habe nur das x eingefügt.
Sirius3
User
Beiträge: 17710
Registriert: Sonntag 21. Oktober 2012, 17:20

@SOS: natürlich funktioniert das nicht, weil Du jetzt ja die Funktion direkt aufrufst und deren Rückgabewert (den es nie geben wird) der after-Methode übergibst:

Code: Alles auswählen

root.after(3000, callback, x)
S0S
User
Beiträge: 50
Registriert: Samstag 9. Februar 2013, 18:59

Ah, okay, dann werde ich das mal überarbeiten, wenn ich Zeit habe :-)
S0S
User
Beiträge: 50
Registriert: Samstag 9. Februar 2013, 18:59

Wenn ich deinen Vorschlag integriere, funktioniert das Zählen mit der after-Methode zwar, aber es zählt los, bevor ich den Strat-Button drücke. Warum? Auch wenn ich stoppe (das funktioniert) und dann auf den Start-Button drücke, passiert nichts.

Code: Alles auswählen

import Tkinter
import time
s = 0

def ende():
    global s
    s = 1
    print "stopped"

def callback(x):
    if s == 0:
        print "Callback", x
        x=x+1
        root.after(3000, callback, x)

root = Tkinter.Tk()

def main():


    # create a menu
    menu = Tkinter.Menu(root)
    root.config(menu=menu)

    x = 0
    button = Tkinter.Button(text="Quit", command=ende)
    button2 = Tkinter.Button(text="Start", command=callback(x))
    button.pack()
    button2.pack()
    root.mainloop()

    time.sleep(3)

main()
Zuletzt geändert von Anonymous am Dienstag 26. Juli 2016, 20:33, insgesamt 1-mal geändert.
Grund: Quelltext in Python-Codebox-Tags gesetzt.
BlackJack

@S0S: Das läuft los weil Du die `callback()`-Funktion in Zeile 27 *aufrufst*. Als `command`-Argument wird der Rückgabewert von ``callback(x)`` übergeben, also `None`, weil die Funktion nichts zurück gibt. Man kann jetzt auf `functools.partial()` zurückgreifen um das zu lösen, aber da immer noch eine Variablen existieren, sollte man besser gleich einen objektorientierten Ansatz wählen und das mit den globalen Variablen sein lassen.
Benutzeravatar
Kebap
User
Beiträge: 686
Registriert: Dienstag 15. November 2011, 14:20
Wohnort: Dortmund

S0S hat geschrieben: Das ist der Beispielcode, den ich im Internet gefunden habe. Ich habe nur das x eingefügt.
Nein, du hast auch die Klammern eingefügt. Durch die Klammern wird die Funktion direkt ausgeführt. Während vorher quasi nur der Name der Funktion übergeben wurde, so dass sie später bei Bedarf aufgerufen werden kann wie gewünscht.
MorgenGrauen: 1 Welt, 8 Rassen, 13 Gilden, >250 Abenteuer, >5000 Waffen & Rüstungen,
>7000 NPC, >16000 Räume, >200 freiwillige Programmierer, nur Text, viel Spaß, seit 1992.
S0S
User
Beiträge: 50
Registriert: Samstag 9. Februar 2013, 18:59

Okay, ich habe es jetzt mal mit einem objektorientierten Ansatz versucht:

Code: Alles auswählen

from __future__ import division

import Tkinter
import datetime
import urllib

root = Tkinter.Tk()

def connected():     # prueft, ob Internetverbindung vorhanden (google.de erreichbar)
    try:
        urllib.urlopen("http://www.google.de")
    except IOError:
        return False
    else:
        return True
    

class inetconnection:

    def __init__(self):
        self.__stop = 0
        with open("inetconnection.txt", "a") as datei:  # schreibt Datum und Uhrzeit des Programmstarts in Datei, ausserdem, ob Internetverbindung vorhanden
            jetzt = datetime.datetime.now()
            datei.write("{}.{}.{}".format(jetzt.day, jetzt.month, jetzt.year) + "\n")
            self.__inet = connected()
            if self.__inet == True:
                datei.write("{}:{}:{} - Internet da\n".format(str(jetzt.hour).rjust(2,"0"), str(jetzt.minute).rjust(2,"0"), str(jetzt.second).rjust(2,"0")))
                self.__online = 1
                self.__offline = 0
            else:
                datei.write("{}:{}:{} - Internet weg\n".format(str(jetzt.hour).rjust(2,"0"), str(jetzt.minute).rjust(2,"0"), str(jetzt.second).rjust(2,"0")))
                self.__online = 0
                self.__offline = 1

        self.__button = Tkinter.Button(text="Quit", command=self.ende)                  # Erstellung der GUI-Elemente
        self.__button2 = Tkinter.Button(text="Start", command=self.check_inet_connection)
        self.__button2.pack()
        self.__button.pack()
        self.__label = Tkinter.Label(root, text="bitte auf Start klicken")
        self.__label.pack()

    def check_inet_connection(self):    # prueft jede Minute die Internetverbindung, schreibt bei Aenderung Ergebnis in Datei und zaehlt Online- und Offline-Minuten
        if self.__stop == 0:
            self.__label.config(text = "Programm lauft...")
            with open("inetconnection.txt", "a") as datei:
                jetzt = datetime.datetime.now()
                inet_neu = connected()
                if inet_neu == True:
                    if inet_neu != self.__inet:
                        datei.write("{}:{}:{} - Internet da\n".format(str(jetzt.hour).rjust(2,"0"), str(jetzt.minute).rjust(2,"0"), str(jetzt.second).rjust(2,"0")))
                    self.__online = self.__online + 1
                else:
                    if inet_neu != self.__inet:
                        datei.write("{}:{}:{} - Internet weg\n".format(str(jetzt.hour).rjust(2,"0"), str(jetzt.minute).rjust(2,"0"), str(jetzt.second).rjust(2,"0")))
                    self.__offline = self.__offline + 1
                self.__inet = inet_neu
            root.after(60000, self.check_inet_connection)

    def ende(self):          # beendet die Schleife zur Pruefung der Interntverbindung, schreibt gesamte Online- und Offline-Zeit in Datei
        self.__stop = 1
        jetzt = datetime.datetime.now()
        with open("inetconnection.txt", "a") as datei:
            datei.write("{}:{}:{} - Ende\n".format(str(jetzt.hour).rjust(2,"0"), str(jetzt.minute).rjust(2,"0"), str(jetzt.second).rjust(2,"0")))
            self.__onlinep = round(self.__online / (self.__online + self.__offline) * 100, 1)
            self.__offlinep = round(self.__offline / (self.__online + self.__offline) * 100, 1)
            datei.write("online: {} Minuten ({}%), offline: {} Minuten ({}%)\n".format(self.__online, self.__onlinep, self.__offline, self.__offlinep))
        self.__label.config(text = "Programm kann geschlossen werden")


def main():
    a = inetconnection()
    root.title("inetconnection")
    root.mainloop()

if __name__ == "__main__":
    main()
Zuletzt geändert von Anonymous am Mittwoch 27. Juli 2016, 22:51, insgesamt 1-mal geändert.
Grund: Quelltext in Python-Codebox-Tags gesetzt.
BlackJack

@SOS: Mit `root` gibt es immer noch eine globale Variable.

Bei den beiden Schaltflächen wird es zudem nicht übergeben.

Der Klassenname entspricht nicht den Konventionen für Klassennamen. Ausserdem ist er IMHO inhaltlich nicht richtig, denn die Klasse repräsentiert keine Internetverbindung. Ich hätte auch ein wenig Probleme einen besseren Namen zu finden, weil es IMHO einfach nur nahezu das gesamte Programm und die globalen Variablen in eine Klasse geworfen sind, also im Grund das gleiche wie vorher. Dann kann man auch bei ``global`` bleiben wenn man es mit einer Klasse genau so macht. Ein weiterer hinweis, dass es eigentlich keine Klasse ist, wäre das zwar ein Exemplar daraus erzeugt und an einen Namen gebunden wird, dieser Name dann aber gar nicht verwendet wird.

In Python 2 sollte man von `object` erben wenn man sonst keine Basisklasse hat. Sonst funktioniert nicht alles so wie es in der Dokumentation beschrieben ist.

Die doppelten führenden Unterstriche sollten alle höchstens ein führender Unterstrich sein. Oder auch gar keiner. Ein Objekt ohne jegliche öffentliche Attribute und Methoden die von aussen nie aufgerufen werden ist ein weiterer „code smell“.

Für ”flags” gibt es Wahrheitswerte (`False`/`True`) die man dann auch nehmen sollte statt 0 und 1. Anstelle vom `stop`-Attribut würde ich aber auch eher die ID speichern die von `after()` zurückgegeben wird, und mit der man den Aufruf der übergebenen Funktion wieder verhindern kann.

Viel Code wiederholt sich. Ebenso der Dateiname für die Protokolldatei. Das sollte nicht sein.

Vergleiche mit literalen Wahrheitswerten machen keinen Sinn. Da kommt nur wieder ein Wahrheitswert heraus, da hätte man auch gleich den verwenden können, den man schon hatte. Oder dessen Negation mit `not` falls man das Gegenteil testen möchte.

Das Formatieren der Zeitangaben könnte man kaum umständlicher machen. Statt `str()` und `rjust()` und alle Einzelteile umzuwandeln kann man das mit *einem* Platzhalter machen bei dem die speziellen Formatierungsangaben für `datetime`-Objekte verwendet. Beispiel: ``'Es ist {0:%H:%M:%S} Uhr.'.format(jetzt)``

Nummerierte Namen sind in der Regel ein Zeichen für Faulheit bei der Namenswahl, oder das man eigentlich eine Datenstruktur statt einzelner Namen haben wollte. `button` und `button2` sind schlechte Namen. Die verraten nichts über die Bedeutung der Werte dahinter ausser dem Typ.

Die Namen `onlinep` und `offlinep` sind ebenfalls nicht gut gewählt, weil man erst raten muss was das `p` am Ende heissen soll. Das wären auch beides keine Attribute sondern lokale Namen. Hier sind auch wieder Codewiederholungen die man in eine Funktion heraus ziehen sollte.
sebastian0202
User
Beiträge: 168
Registriert: Montag 9. Mai 2016, 09:14
Wohnort: Berlin

Hallo,


mal eine Frage:
Wäre es nicht besser einen dauerhaften ping (Windows -t Option) abzusetzen,
anstelle eines immer wiederholenden urllib.urlopen? :? (weniger Performance lastig?)

Der Ping müsste doch dann als separater Thread laufen und die Daten müssten mittels Queue ausgetauscht werden?
Also immer wieder abfragen ob neue Daten auf dem Stream liegen und diese dann auswerten.
BlackJack

@sebastian0202: Naja, ob man nun einmal in der Minute einen Ping absetzt oder versucht Kontakt zu einem Webserver aufbaut (ohne die Seite herunterzuladen) dürfte jetzt keinen so gravierenden Unterschied machen.
S0S
User
Beiträge: 50
Registriert: Samstag 9. Februar 2013, 18:59

BlackJack, vielen Dank für die ausführliche Kritik.

Ja, es stimmt, letztendlich habe ich das ganze Programm (inkl. globaler Variablen) in einer Klasse geschoben. Ein sinnvollerer Ansatz ist mir nicht eingefallen und es scheint mir bei einem solch kurzen Programm eigentlich nicht besonders sinnvoll, auf Teufel komm raus, mehrere Klassen einzuführen. Ich verstehe auch noch nicht so ganz, was eigentlich so schlimm an globalen Variablen ist. Oft machen die Workarounds, um diese zu vermeiden, den Code aus meiner Sicht eher unübersichtlicher.

In meinem Programmierkurs an der Uni, der allerdings für eine andere Programmiersprache war, habe ich gelernt, dass Klassenattribute normalerweise immer privat sein sollten, und man - wenn nötig - mit entsprechenden get- und set-Methoden darauf zugreift. Deinem Kommentar entnehme ich, dass man es damit in Python nicht so genau nimmt und die Variablen nur als protected deklariert und es somit dem evtl. Nutzer überlässt, was er damit anfängt?

Das einzige, was ich an Codewiederholung sehe, ist das Schreiben der Uhrzeiten in eine Datei. Das wäre allerdings immer nur eine Zeile, die man in eine Funktion auslagern würde, wodurch der Code weder kürzer noch übersichtlicher wird.

Unter Berücksichtigung deiner Anmerkungen komme ich dann auf folgendes:

Code: Alles auswählen

from __future__ import division

import Tkinter
import datetime
import urllib

def connected():     # prueft, ob Internetverbindung vorhanden (google.de erreichbar)
    try:
        urllib.urlopen("http://www.google.de")
    except IOError:
        return False
    else:
        return True
        
    
class Programmdurchlauf(object):

    def __init__(self, logdatei):

        self._stop = False
        self._logdatei = logdatei
        
        with open(self._logdatei, "a") as datei:    # schreibt Datum und Uhrzeit des Programmstarts in Datei, ausserdem, ob Internetverbindung vorhanden
            jetzt = datetime.datetime.now()
            datei.write(jetzt.strftime("%d.%m.%Y\n"))
            self._inet = connected()
            if self._inet:
                datei.write(jetzt.strftime("%H:%M:%S - Internet da\n"))
                self._online = 1
                self._offline = 0
            else:
                datei.write(jetzt.strftime("%H:%M:%S - Internet weg\n"))
                self._online = 0
                self._offline = 1

    def gui_erstellen(self):            # erstellt die GUI
        self._root = Tkinter.Tk()                             
        self._root.title("inetconnection")
        self._stop_button = Tkinter.Button(self._root, text="Quit", command = self.ende)
        self._start_button = Tkinter.Button(self._root, text="Start", command = self.check_inet_connection)
        self._start_button.pack()
        self._stop_button.pack()
        self._label = Tkinter.Label(self._root, text="bitte auf Start klicken")
        self._label.pack()
        self._root.mainloop()
        
    def check_inet_connection(self):    # prueft jede Minute die Internetverbindung, schreibt bei Aenderung Ergebnis in Datei und zaehlt Online- und Offline-Minuten
        if not self._stop:
            self._label.config(text = "Programm lauft...")
            with open(self._logdatei, "a") as datei:
                jetzt = datetime.datetime.now()
                inet_neu = connected()
                if inet_neu:
                    if inet_neu != self._inet:
                        datei.write(jetzt.strftime("%H:%M:%S - Internet da\n"))
                    self._online = self._online + 1
                else:
                    if inet_neu != self._inet:
                        datei.write(jetzt.strftime("%H:%M:%S - Internet weg\n"))
                    self._offline = self._offline + 1
                self._inet = inet_neu
            self._root.after(60000, self.check_inet_connection)

    def ende(self):          # beendet die Schleife zur Pruefung der Interntverbindung, schreibt gesamte Online- und Offline-Zeit in Datei
        self._stop = True
        jetzt = datetime.datetime.now()
        with open(self._logdatei, "a") as datei:
            datei.write(jetzt.strftime("%H:%M:%S - Ende\n"))
            self._onlineprozent = round(self._online / (self._online + self._offline) * 100, 1)
            self._offlineprozent = round(self._offline / (self._online + self._offline) * 100, 1)
            datei.write("online: {} Minuten ({}%), offline: {} Minuten ({}%)\n".format(self._online, self._onlineprozent, self._offline, self._offlineprozent))
        self._label.config(text = "Programm kann geschlossen werden")


def main():
    a = Programmdurchlauf("inetconnection.txt")
    a.gui_erstellen()


if __name__ == "__main__":
    main()
BlackJack

@S0S: Es geht nicht darum auf Teufel komm raus Klassen zu haben, sondern sauber zu programmieren, ohne globalen Zustand der das ganze Programm durchzieht. ``global`` ist der Workaround, nicht anders herum.

Python hat keine ”private”-Attribute, insbesondere sind die doppelten führenden Unterstriche nicht ”private”, sondern für einen ganz anderen Zweck gedacht. Man hat damit weiterhin Attribute auf die jeder von aussen zugreifen kann, die heissen bloss anders, um Namenskollisionen zu vermeiden bei Mehrfachvererbung oder tiefen Vererbungshierarchien. Beides kommt in Python selten vor, deshalb auch die doppelten führenden Unterstriche nur selten. Man kann auch nichts als ”protected” *deklarieren*. Es gibt die Konvention das *ein* führender Unterstrich bedeutet, dass es sich um ein Implementierungsdetail handelt. Wo man von aussen nicht drauf zugreifen sollte, solange man nicht genau weiss, was man da tut.

Ich sehe die Zeilen 22 bis 33 und 45 bis 56 die sehr ähnlich sind. Das ist deutlich mehr als eine Zeile. Dort und noch an anderer Stelle wird etwas mit einem Zeitstempel in eine Protokolldatei geschrieben, das könnte man auch heraus ziehen, statt es immer wieder auszuprogrammieren.

Die Prozentberechnung steht auch zweimal im Programm.

`Programmdurchlauf` ist auch kein wirklich guter Name.
S0S
User
Beiträge: 50
Registriert: Samstag 9. Februar 2013, 18:59

Hallo BlackJack,

die Attribute mit zwei führenden Unterstrichen verwirren mich noch etwas. Auf dieser Seite (http://www.python-kurs.eu/klassen.php) ziemlich weiter unten unter der Überschrift Datenkapselung steht, dass Attribute, deren Name mit __ beginnen, privat sind, sodass man auf sie nicht von außen zugreifen kann. So werden sie auch im darunterstehenden Beispiel verwendet. Dies habe ich mit folgendem Code ausprobiert, der das auch bestätigt:

Code: Alles auswählen

class Neu(object):
    def __init__(self, attr):
        self.__attr = attr

a = Neu(5)
print a.__attr
Was meinst du damit, dass man auf diese Attribute dennoch von außen zugreifen kann? Sirius3 schrieb im anderen Thread ebenfalls, dass doppelte Unterstriche nichts in einem Programm ohne Mehrfachvererbung zu suchen haben, was aber offensichtlich nicht die Verwendung ist, die auf der oben verlinkten Seite angewendet wird. Sollte man es so also generell nicht machen, sondern lediglich protected-Variablen mit einem führenden Unterstrich verwenden, um zu signalisieren "normalerweise nicht verändern"?
BlackJack

@S0S: Es gibt in Python weder ”private” noch ”protected”, das ist verwirrend in dem Zusammenhang diese Begriffe zu verwenden, die eine recht feste Bedeutung haben. Quellen die so etwas behaupten, sollte man mit Vorsicht geniessen. Nur weil etwas im Internet steht, muss es nicht wahr sein. ;-)

Nochmal: Doppelte führende Unterstriche machen nichts ”private”. Die Attribute sind weiterhin öffentlich verfügbar, nur unter einem anderen Namen um Namenskollisionen, zum Beispiel bei Mehrfachvererbung zu vermeiden:

Code: Alles auswählen

In [5]: class Neu(object):
   ...:         def __init__(self, attr):
   ...:                 self.__attr = attr
   ...: 

In [6]: a = Neu(5)

In [7]: a._Neu__attr
Out[7]: 5
Das Muster nach dem der Name verändert wird ist dokumentiert, es ist also kein Problem darauf zuzugreifen. Es verhindert bei Mehrfachvererbung mit zwei Klassen die den gleichen Attributnamen, aber für unterschiedliche Zwecke verwenden, dass diese Namen kollidieren, weil sie sich durch den jeweiligen Klassennamen unterscheiden, der hinzugefügt wurde. (Allerdings kann einem dann immer noch auf die Füsse fallen wenn es weiter oben in der Vererbungshierarchie eine Weitere Klasse mit dem gleichen Namen und Attribut gibt dem zwei Unterstriche vorangestellt sind. :-))

Ein Unterstrich sagt nicht ”normalerweise nicht verändern”, sondern generell nicht zugreifen. Jedenfalls solange man nicht weiss was man tut, oder bereit ist die Risiken zu tragen.
Sirius3
User
Beiträge: 17710
Registriert: Sonntag 21. Oktober 2012, 17:20

@S0S: nicht alles, was auf irgendwelchen Seiten steht, muß stimmen. Es gibt in Python keinen Zugriffsschutz, also sind Bezeichnungen wie protected oder private einfach nur falsch. _name heißt nur, dass man nicht von außen zugreifen soll, nicht mal lesend.

Die erste Frage, die sich mir bei Deinem Programm stellt, ist ja die, warum es da überhaupt eine GUI gibt.
Die Funktionalität sollte idealerweise auch ohne GUI funktionieren.

Du hast nur «global» definierte Variablen durch mit »self.« eingeleitete ersetzt. Eine Gott-Klasse ist genauso unübersichtlich, wie globale Variablen zu verwenden. Das ist nicht nur Ideologie, sondern sorgt dafür, dass Programme lesbar, wartbar und testbar bleiben.
S0S
User
Beiträge: 50
Registriert: Samstag 9. Februar 2013, 18:59

Ok, ich merke mir, dass der doppelte Unterstrich für etwas ganz anderes gedacht ist als das "Verstecken" von Attributen und ich ihn, sofern ich nicht mit Vererbung arbeite, was ich bisher noch nie getan habe, nicht verwende. Der einfache Unterstrich tut das, was ich auch dachte, also vom Programm her gar nichts, aber es ist eine Konvention, auf derartige Attribute nicht direkt zuzugreifen.

Die GUI habe ich in das Programm eingeführt, da ich eine Möglichkeit gesucht habe, beim Beenden der Schleife zu einem Zeitpunkt, den ich selbst bestimme, noch Befehle auszuführen (konkret: die Gesamtzahl der online- und offline-Minuten berechnen und in die Datei schreiben). Für die Entscheidung "Wenn ich nichts tue, führe die Schleife weiter aus, wenn ich etwas tue (klicken oder auch irgendeine Eingabe), beende die Schleife und mache das." habe ich keine nicht-gui-basierte Möglichkeit der Umsetzung gefunden, sondern bin nur immer wieder auf die after-Methode gestoßen.
Antworten