Path: csiph.com!fu-berlin.de!uni-berlin.de!not-for-mail From: Stefan Schwarzer Newsgroups: de.comp.lang.python Subject: =?utf-8?q?=5BPython-de=5D_Re=3A_Code_Style_Review?= Date: Tue, 29 Nov 2022 18:18:38 +0100 Lines: 109 Message-ID: <25b8d1d4-d6e2-22ee-4bed-ec76227fa65d@sschwarzer.net> References: Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8; format=flowed Content-Transfer-Encoding: 8bit X-Trace: news.uni-berlin.de qBKz0Hz4aZhBKXJloyjzSA2weocr/nJlrVcl7+OpaXoA== Authentication-Results: mail.python.org; dkim=none reason="no signature"; dkim-adsp=none (unprotected policy); dkim-atps=neutral User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.8.1.24) Gecko/20100411 Thunderbird/2.0.0.24 Mnenhy/0.7.6.666 Content-Language: en-US, de-DE In-Reply-To: X-Provags-ID: V03:K1:uN5u9vwMG9TixiKXSH+Sgqovkq2odiabjt/+92iASwHYDLdzR+L smx+usqRLM+Txdw48AKGZSdy1szuc6d4hGZCt5UbDW1qTe6gkAxES9KQNhn/2114ZFxLTKW OvOzoaKYngI3SUx8+24Q6aWdF2JoxGHpjQ8busREfPkMuJ4/p8cT+njA7LAD0JEatfROyOk XhI8sehi3XAqUyHjY1pkQ== X-Spam-Flag: NO X-UI-Out-Filterresults: notjunk:1;V03:K0:mrf5c9nnol8=:fMNhitx3eOFGd2l83kzjPW BbKqwFn5KHHtUKJDwkAsGgMwIRNTSwTQujzl0fXUsnIvMq1Kxwz3YMGHwTZ8zgRezsWnHE+Dn a0Zq0Bo5xSRAte7e+Ec953jHnOQNvN9Ya878LXGv1k3QG8bzLQpP3rajcm4vEOginVst5Abxo poglGDPpBryEdUqmhBH8CI13GYHWDpZkDlf4lDIX9exmj7Ab/VFUZwJOqiZ6uHWVTnYLEXWxC +ieOTPcuuDGlQrLh/Ts2oFVjDS8gUKbqsC3ckZTZ0OLDx/cH4id1/xUHdWvkTzStqmJZY4H/a JD1X85L9cbi3+kt44J7Ps28OibbDULDqz1n14FFuzloMGqyf1qahTft3DkemaWtM7PeSyuo9p lGSO9T6lG8vcBwvk/EbIr4YrXhZl3fcG2RCKxkPY/tXM6+e0FY3jqs7G1ZpVg5I5cksq133fR BbbCASToDqUxhkVYH6HpZOXnY2jabeDjJiYmzoMJdCcZeCvzTILrOMNP8gLHvf9FXakcOtz6Y 7vv3FuTjo+xbJ2hqL6jVMzpj8cVthFprmd0T0mzSIUgRVJ7t0DXxmky5ymJsv+BxVqAF8+DQl Lx0jgIH11UfJG9nlBebMLjmqkOPL51Z8IvQSn2GSaDKCz5NK6uxfKOhR2vBOkruXIz/A597rN I1qTs0PgitppASXJWAeBylUF8DbtXvEMUQryQFURKiDctVLDMowaf7owMa8w2iLCuIOtmG3+S MfILel8fsUU+6gX+loCYM+UBXqjXB35rs/+sswEZ14PTWgUc4CcXg0wX/3kXpQ7gKR5+stTqU 4H5TmrT0fl67KoBWa+cgy7p/Vg6kQ== Message-ID-Hash: Y6YXVAICX37E63AP654EAJ5NDBZNH4W5 X-Message-ID-Hash: Y6YXVAICX37E63AP654EAJ5NDBZNH4W5 X-MailFrom: sschwarzer@sschwarzer.net X-Mailman-Rule-Misses: dmarc-mitigation; no-senders; approved; emergency; loop; banned-address; member-moderation; header-match-python-de.python.org-0; nonmember-moderation; administrivia; implicit-dest; max-recipients; max-size; news-moderation; no-subject; digests; suspicious-header X-Mailman-Version: 3.3.7 Precedence: list List-Id: Die Deutsche Python Mailingliste Archived-At: List-Archive: List-Help: List-Owner: List-Post: List-Subscribe: List-Unsubscribe: Xref: csiph.com de.comp.lang.python:5873 Hallo Marc, On 2022-11-28 16:19, Marc Haber wrote: > ich wollte mich schon seit Jahren mal etwas ernsthafter mit python > beschäftigen und hier ist mein Erstlingswerk signifikanter Länge. > pylint hat nichts auszusetzen, an manchen Stellen habe ich pylint aber > überstimmt. > > Ist da irgendetwas drin, was nicht pythonesk genug formuliert ist? > > Laufen tut das Programm jedenfalls. > > Ich würde mich über Eure Kommentare freuen. ich habe hier und da ein paar Anregungen. Wie immer gilt, dass letztlich der Autor entscheidet, wie er/sie diese Anregungen umsetzt. :-) Erst mal zum Thema der Konfigurations-Speicherung, was in dem Diskussions-Thread auch aufgegriffen wurde. Da in Python Module und Klassen natürliche Singletons sind, wäre mein Vorschlag, die Konfigurations-Daten in einer Klasse zu speichern, also ``` class config: # Listener IP address and port of MQTT server. ip_address = None port = None # If `True`, print debugging output. debug = False ... ``` Du kannst einfach von überall aus dem Modul auf das `config`-Objekt zugreifen und brauchst auch kein `global`. Die Klasse wird nie instanziiert, sondern nur als Namespace benutzt. Der Ansatz hat gegenüber dem `config`-Dictionary auch den Vorteil, dass du dokumentieren kannst, wofür die einzelnen Werte gedacht sind. Ich halte es für gut, in `config` alle Werte auf Default-Werte zu setzen, selbst wenn diese mangels eines sinnvollen Defaults erst mal `None` sind. Das hat den Vorteil, dass man sehen kann, was jemals gesetzt wird und reduziert die Verwirrung, weil man nicht zwischen `None` und "gar nicht gesetzt" unterscheiden muss. (Ich habe tatsächlich mal Code gesehen, wo ein Dictionary zur Datenübergabe verwendet wurde und die Abwesenheit eines Keys eine andere Bedeutung hatte als der Key mit dem Wert `None`. Das fand ich sehr verwirrend.) Ich würde die Kommandozeilen-Optionen von den `config`-Attributen getrennt halten, um nicht die Konzepte Kommandozeilen-Parsen und Konfiguration zu vermischen. Das ist aber vielleicht ein Detail. Ich empfehle, falls möglich die `config`-Klasse erst mit allen gewünschten Werten zu füllen oder zu überschreiben und dann nur noch lesend darauf zuzugreifen. Zu den Debug-Ausgaben: Da kannst du den Code etwas vereinfachen, indem du die Abfrage des Debug-Flags in eine Funktion verschiebst, die du aufrufst. Also statt ``` if config.debug: print(...) if config.debug: print(...) if config.debug: print(...) ``` eher ``` def debug_print(*args, **kwargs): if config.debug: print(*args, flush=True, **kwargs) debug_print(...) debug_print(...) debug_print(...) ``` (Bei der Gelegenheit kannst du noch wie oben ein `flush=True` spendieren, was beim Debuggen von nebenläufigem Code für eine übersichtlichere Ausgabe sorgen kann.) Für `element` würde ich statt Dictionarys `namedtuple`s oder Instanzen von `SimpleNamespace` verwenden. Allgemein sehen Zugriffe auf Dictionarys aus meiner Sicht immer recht "noisy" aus. Es gibt vermutlich noch mehr zu verbessern, aber das kann ich jetzt nicht so leicht überblicken. Oft geht solches Aufräumen iterativ besser, also bewerten, verbessern, neu bewerten, weiter verbessern usw. Viele Grüße Stefan