requests vs. urllib

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
Sophus
User
Beiträge: 1109
Registriert: Freitag 25. April 2014, 12:46
Wohnort: Osnabrück

Wie wäre es denn richtig, um eine strikte Trennung beizubehalten?
Benutzeravatar
Sophus
User
Beiträge: 1109
Registriert: Freitag 25. April 2014, 12:46
Wohnort: Osnabrück

Um das Thema Trennung von Logik und GUI nochmal aufzugreifen habe ich mal einen Ausschnitt aus meiner bisherigen Entwicklung angefertigt:

Code: Alles auswählen

VERSION = "0.0.1"
import os
import sys
import urllib2

from PyQt4.QtGui import QDialog
from PyQt4.uic import loadUi

class Update_Window(QDialog):
    def __init__(self, parent=None):
        QDialog.__init__(self, parent)

        self.getPath_update = os.path.abspath(os.path.join('files', "qt_ui", 'pp_update.ui'))

        self.ui_pp_update = loadUi(self.getPath_update, self)

    def create_actions_buttons(self):
        self.ui_pp_update.pushButtonCheck_Update.clicked.connect(self.check_update)
        self.ui_pp_update.pushButtonUpdate.clicked.connect(self.get_update)

    def get_update(self):
        pass
        # The zip file should be downloaded

    def check_update(self):
        try:
            data = urllib2.urlopen('http://sophus.bplaced.net/changelog/version.txt').read()
            if str(data) > str(VERSION):

                self.ui_pp_update.labelUpdate.setText('Software Update', 'Update Available!')
                self.ui_pp_update.pushButtonUpdate.setEnabled(True)
            else:
                self.ui_pp_update.labelUpdate.setText('Software Update', 'No Updates are Available.')
                self.ui_pp_update.pushButtonUpdate.setEnabled(False)
        except Exception as ex:
            self.ui_pp_update.labelUpdate.setText('Software Update: Unable to Check for Update', ex)
            self.ui_pp_update.pushButtonUpdate.setEnabled(False)

if __name__ == '__main__':
    app = Update_Window()
    app.show()
    sys.exit(app.exec_())
Wenn ich euch also richtig verstanden habe, dann findet in der check_update()-Funktion keine wirklich Trennung statt? Die Funktion liest eine Textdatei vom Webserver, vergleicht die Versionsnummern, und dementsprechend werden die Schaltflächen behandelt. Auch wird der Anwender über die Labels entsprechend benachrichtigt, ob nun eine neue Version vorliegt oder nicht. Sehe ich das also richtig, dass ich hier GUI und Logik vermische? Wenn ja, wie wäre eure Herangehensweise?
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

Ich hatte es ja eigentlich schon in diesem Beitrag genannt: Du musst das über einen *Rückgabewert* regeln! Du könntest z.B. eine Funktion (also *außerhalb* der Klasse und somit der GUI!) schreiben, die ``updates_available`` heißt und einfach ``True`` oder ``False`` zurückliefert. Diese rufst Du dann *in* ``check_update`` (imho kein guter Name) auf und steuerst anhand des *Rückgabewertes* der reinen Domänenfunktion das weitere Vorgehen, also Button entsperren usw.

Einfach, oder? ;-)

Im Grunde hatten wir das alles ja schon zu Beginn Deiner Foren-Beteiligung hier. Schau Dir doch noch mal den Thread an und dort in diesem Beitrag die Zeilen 7+8 und Zeile 22. Die Situation dort ist exakt dasselbe Problem, welches wir hier haben. Die GUI nutzt externe Funktionalität, indem sie eine Funktion aufruft (dort sogar mit Parametern) und den *Rückgabewert* nutzt, um den weiteren Ablauf zu steuern.
Zuletzt geändert von Hyperion am Donnerstag 23. April 2015, 08:42, insgesamt 1-mal geändert.
Grund: Verweis auf altes Beispiel hinzugefügt
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
Benutzeravatar
Sophus
User
Beiträge: 1109
Registriert: Freitag 25. April 2014, 12:46
Wohnort: Osnabrück

@Hyperion: Zwei Dinge: Ich habe hier echt komplizierter Gedacht, und zwar an das MVC-Konzept. Dazu hatte ich mir gestern gegen 1 Uhr noch dieses "Tutorial" studiert: MVC design with QtDesigner and PySide. Da dachte ich mir schon "Oh mein Gott" :-) Und zum anderen hätte ich zum BlackJacks Beispiel mit seinem BMI-Rechner eine Frage. Nun, ist die Trennung von Logik und GUI erst gegeben, wenn die Funktionen außerhalb der Klasse geschrieben wird? In BlackJacks wurde die Funktion ja außerhalb Klasse, jedoch innerhalb des selben Moduls geschrieben. Man könnte ja auch die Funktion in ein weiteres Modul schreiben und blah.

Ich dachte (Juhu, ich kann denken :-)), die Trennung wäre auch gegeben, wenn ich die Funktion innerhalb der selben Klasse schreibe, in die auch die GUI geladen wird, und ich nur darauf achten muss, dass hierbei die Funktion und GUI sich nicht intensiv in Berührung kommen? Ich verstehe BlackJacks Vorgehen insofern nicht, weil ich mir sagen, auch wenn die Funktion innerhalb der Klasse geschrieben wird, ist sie wartbar. Ich meine, für ein anderes Projekt kann ich die Funktion dann kopieren und verwenden. Oder dient dies nur zur Veranschaulichung?

Und wieso stellst du das Wort Rückgabewert in Anführungszeichen? Willst du damit sagen, dass es sich nicht wirklich um einen Rückgabewert handelt?
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

Sophus hat geschrieben:Nun, ist die Trennung von Logik und GUI erst gegeben, wenn die Funktionen außerhalb der Klasse geschrieben wird?
Ja! Denn das ermöglicht schon mal das Unit Testen und ggf. auch das Benutzen in anderen Projekten. Dazu importiert man dann eben nur die Funktionen (bzw. allg. Objekte), die man auch benötigt.

Bei komplexeren Sachen würde ich aber dazu tendieren, die Domänen spezifischen Dinge auf jeden Fall in ein separates Modul zu packen, wenn nicht sogar in verschiedene Pakete!

Letztlich steigert das den Grad der Unabhängigkeit vom simplen "testbar" bis hin zur einfachen Wiederverwendbarkeit in vollständig anderen Projekten. Bei kleineren Sachen finde ich es aber auch ok alles in einem Modul zu belassen - dann aber eben sauber getrennt. Dies ist übrigens natürlich unabhängig von Klassen und Funktionen, sondern betrifft alle denkbaren Python Konstrukte. Das Entkoppeln von IO-Operationen und Domänenlogik ist ein anderer oft auftretender Anwendungsfall btw.
Sophus hat geschrieben: Ich dachte (Juhu, ich kann denken :-)), die Trennung wäre auch gegeben, wenn ich die Funktion innerhalb der selben Klasse schreibe, in die auch die GUI geladen wird, und ich nur darauf achten muss, dass hierbei die Funktion und GUI sich nicht intensiv in Berührung kommen?
Nein, dann natürlich nicht, weil Du dann "GUI"-Code und "nicht GUI"-Code nicht *separat* verwenden kannst. (Von ``staticmethod`` mal abgesehen, aber das wäre imho dennoch schlechtes Design!)

Ich hatte Dir schon damals im ganz alten Thread empfohlen, Dir mal Unit Testing anzugucken. Spätestens dann wirst Du kapieren, *wieso* solche Trennungen sehr sinnvoll sind. Evtl. solltest Du Dir auch mal "Clean Code" von Onkel Bob (aka. Robert C. Martin) durchlesen - das wird Dir viel bringen :-)
Sophus hat geschrieben: Und wieso stellst du das Wort Rückgabewert in Anführungszeichen? Willst du damit sagen, dass es sich nicht wirklich um einen Rückgabewert handelt?
Es handelt sich nicht um Anführungszeichen, sondern um Asteriske also *. Dies ist in vielen Markupsprachen (Creole iirc, div. Wikis, Emails (!)) ein Markup zur Hervorhebung von Wörtern. Oftmals ist die mir das altbackene Markup dieses Boards zu kompliziert zu tippen und ich greife dann auf diese Alternative zurück :-)
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
Antworten