Python 'Benzingespräche'

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
kbr
User
Beiträge: 1487
Registriert: Mittwoch 15. Oktober 2008, 09:27

ulipy hat geschrieben: Mittwoch 1. Dezember 2021, 17:05 Du gibst nun dem user beim initialen Start die Möglichkeit, keinen oder auch jeden dieser Werte an seine Bedürfnisse anzupassen (kein GUI, Kommandozeile).
Dann schreibst du das fest auf Platte.
Das, was danach von Platte gelesen wird, sind per Definition user settings.
Aus dem script wird das danach "nie mehr" benötigt oder gelesen.
Es gibt viele Wege zum Ziel. Ich gebe Dir mal ein Beispiel, wie es umgesetzt werden könnte:

Code: Alles auswählen

from configparser import ConfigParser
from pathlib import Path


SETTINGS_FILE = Path().resolve().parent / "configuration.ini"
SETTINGS_FILE_ENCODING = "utf-8"


def get_settings(settings_file):
    """
    Takes a Path-instance as settings_file and
    returns a dictionary with the settings.
    """
    defaults = {
        'del_orphaned': False,
        'demo_only': False,
        'hide_versions': False,
        'symlinks_dirs': False,
        'symlinks_files': False,  
    }
    config = ConfigParser(defaults=defaults)
    if settings_file.exists():
        with open(settings_file, "r", encoding=SETTINGS_FILE_ENCODING) as fobj:
            config.read_file(fobj)
            defaults = dict(config.items("DEFAULT"))
    else:
        with open(settings_file, "w", encoding=SETTINGS_FILE_ENCODING) as fobj:
            config.write(fobj)
    return defaults


settings = get_settings(SETTINGS_FILE)
print(settings)
Du hast hier eine Funktion "get_settings" die Dir die Settings als dictionary zurück gibt. Die Settings werden dabei aus der Datei "configuration.ini" gelesen, die sich im gleichen Verzeichnis wie Dein Skript befinden muß. Existiert diese Datei nicht, dann wird sie angelegt und die default-Werte werden verwendet. Existiert die Datei, dann überschreiben dortige Inhalte die default-Werte.

Das lässt sich alles auch noch schöner und umfangreicher machen (z.B. verschiedene Verzeichnisse, die der Reihe nach für eine .ini Datei durchsucht werden etc.) aber damit kannst Du schon mal ein wenig herumspielen.

Sicherlich erfordert diese Möglichkeit nun eine optionale(!) settings-Datei, aber das ist durchaus sinnvoll.
ulipy
User
Beiträge: 83
Registriert: Mittwoch 17. November 2021, 21:42
Wohnort: Ba-Wü

@alle
Zum Verständnis:
Es geht nicht darum, irgendetwas stur zu verfolgen.

Aus den meisten Beiträgen war m. E. herauszulesen, dass die Informationen des Für und Wider der Verwendung einer Klasse im vorliegenden Fall nicht ausreichend sind.

Dies ist verstanden und hat auf meiner Seite dazu geführt, diese Verwendung zunächst als Option weiter zu entwickeln. Später erst wird man sehen können, was genau an dieser Stelle das "Richtige" ist.

@kbr
was für mich hier nicht klar ist:

Code: Alles auswählen

defaults = {
        'del_orphaned': False,
        'demo_only': False,
        .
        .
"defaults" ist eine Konstante, allerdings "nur" innerhalb einer klasse verwendet.
Würde "defaults" dann tatsächlich nicht wie "DEFAULTS" geschrieben?
Das nur der Vollständigkeit halber.


@Sirius3
sag bitte zur Linderung meiner Schmerzen :D , ob dir wenigstens Zweifel gekommen waren in der Interpretation dieser Platzhalter-Namen?
...
@ulipy: tmp ist selten ein sinnvoller Variablenname, und ...
...
MyClass ist ein sehr schlechter Klassenname, warum..
...
Hier zeigt sich gut, wie schwierig sich manchmal Kommunikation über ein so eingeschränktes Medium gestaltet...

Zur Hilfe bei der rein abstrakten Konstruktion einer Klasse habe ich hier viewtopic.php?f=1&t=53566 eine separate Frage gestellt
Py::: 1. funktional zuverlässig, 2. Anfänger-lesbar, 3. Py-Konformität
Benutzeravatar
kbr
User
Beiträge: 1487
Registriert: Mittwoch 15. Oktober 2008, 09:27

@ulipy:kleingeschrieben ist korrekt. Alternativ ließen sich die Werte auch modul-global zunächst an großgeschriebene Bezeichner binden. Lieber aber wäre es mir, wenn Du Dich mit der Funktion und deren Rückgabewert befasst.
ulipy
User
Beiträge: 83
Registriert: Mittwoch 17. November 2021, 21:42
Wohnort: Ba-Wü

Danke @kbr, ist auf jeden Fall angekommen! Es geht halt nicht alles auf einmal..

Was mir an eine Klasse hier unter anderem sehr gefällt ist z. b. die Möglichkeit, die "versehentliche" Erzeugung eines Attributs durch Verwendung von __slots__ zu verhindern und die klare, einfache Abfrage eines der initialisierten Attribute.

Python lässt dem Programmierer manchmal erschreckend viel Freiheit..
Py::: 1. funktional zuverlässig, 2. Anfänger-lesbar, 3. Py-Konformität
Benutzeravatar
pillmuncher
User
Beiträge: 1482
Registriert: Samstag 21. März 2009, 22:59
Wohnort: Pfaffenwinkel

ulipy hat geschrieben: Freitag 3. Dezember 2021, 22:40 Python lässt dem Programmierer manchmal erschreckend viel Freiheit..
Genau, viel zu viel Freiheit! Und wenn man nicht bei rot über die Straße zu gehen möchte, muss man seine Füße festnageln.

Anders ausgedrückt: Statt dir Mechanismen zu suchen, die irgendwas verhindern - genügt es nicht, es einfach nicht zu tun? Also statt __slots__ dafür zu missbrauchen, Attribute zu verhindern, sie einfach nicht anzulegen? Der einfache Weg ist in Python immer der richtige, außer in sehr wenigen, sehr speziellen Fällen, bei denen der Programmierer idR. genau weiß, warum er vom einfachen Weg abweicht. Was du dagegen tust, ist Probleme für Lösungen zu suchen.
In specifications, Murphy's Law supersedes Ohm's.
ulipy
User
Beiträge: 83
Registriert: Mittwoch 17. November 2021, 21:42
Wohnort: Ba-Wü

@pillmuncher
pillmuncher hat geschrieben: Freitag 3. Dezember 2021, 23:19
ulipy hat geschrieben: Freitag 3. Dezember 2021, 22:40 Python lässt dem Programmierer manchmal erschreckend viel Freiheit..
Genau, viel zu viel Freiheit! Und wenn man nicht bei rot über die Straße zu gehen möchte, muss man seine Füße festnageln.
..
.
Das kann schon so ausssehen - ich suche als Neuling zur Zeit hauptsächlich "trittfesten Boden".

Dazu gehört natürlich das Ausloten von Sprachelementen, ob nun restriktive oder freiere, kreativere. Ohne Nachdenken leicht befolgbare py-sprachlich konkrete Richtlinien habe ich noch kaum.

Eine geänderte Klassenkonstruktion unter Verwendung von __slots__ stelle ich jetzt ins Thema viewtopic.php?f=1&t=53566 rein
Py::: 1. funktional zuverlässig, 2. Anfänger-lesbar, 3. Py-Konformität
ulipy
User
Beiträge: 83
Registriert: Mittwoch 17. November 2021, 21:42
Wohnort: Ba-Wü

Hallo zusammen,
nach dem crash-Einstieg, welcher notwendig chaotisch verlaufen ist und durch eure vielen Beiträge ermöglicht wurde,
habe ich nun eine Vor-Version eines Funktionsobjekts erstellt und versucht, innerhalb eines Levels 1 (von 3) wenigstens Konventionen und Sprachelemente einigermaßen "sauber" zu verwenden.

Die semantisch bedingten Logik-Weichen darin sind hier nicht entscheidend - ein von @__blackjack__ erwähnter Unittest wäre dazu natürlich Gold wert.. - dieser steht derzeit jedoch wie gesagt nicht an.

Wäre sehr dankbar, wenn der Code auf die erkennbaren Python Schwächen abgeklopft werden könnte:

Code: Alles auswählen

import os
import json

# !access settings via this function only please!
def rw_settings(*args):
    """
    Read or write settings
    If no settings-file is found, use defaults
    
    Access / args samples:
    Read:
      rw_settings('read_default_data')
      rw_settings('_symlinks_dirs')
    
    Write:
      rw_settings('_symlinks_dirs', 'True')
    """
    
    if 0 < len(args) > 2:
        # no of args: 1 or 2 only!
        print('!ERROR!   !ERROR!   !ERROR!')
        print('expected 1 or 2 args only, received:', len(args))
        quit()

    # edit data_path for release !!!
    data_path = '.\\dummy_f_dfg_ff__Y_TmP_mydata.json'
    if not os.path.exists(data_path):
        # read defaults
        data = {
            '_del_orphaned': False,   # if true:  del orphaned versions
            '_demo_only': False,      # if true:  demo only
            '_hide_versions': False,  # if true:  hide
            '_symlinks_dirs': False,  # if false: ignore
            '_symlinks_files': False, # if false: ignore
            # 'scan_all_subdirs', # visibility of subdirs for power-user
            }
    else:
        # read from file
        with open(data_path, 'r') as f:
            data = json.load(f)

    if len(args) == 1:
        if args[0] == 'read_default_data':
            # return default dict
            return data
        else:
            # check .json file status
            if not os.path.exists(data_path):
                # write default data to disc
                with open(data_path, 'w') as f:
                   json.dump(data, f)
            else:
                # no action required here
                pass

    if len(args) == 2:
        # update a key-value
        data[args[0]] = args[1]
        # write updated data to disc
        with open(data_path, 'w') as f:
           json.dump(data, f)

    return data[args[0]]


print("rw_settings('read_default_data'):")
print(rw_settings('read_default_data'))

print("rw_settings('_demo_only'):")
print(rw_settings('_demo_only'))

print("rw_settings('read_default_data'):")
print(rw_settings('read_default_data'))

print("rw_settings('_demo_only', 'True'):")
print(rw_settings('_demo_only', 'True'))

print("rw_settings('_demo_only', 'True', 'one arg excess'):")
print(rw_settings('_demo_only', 'True', 'one arg excess'))

Die unten stehenden calls wurden nicht auf Vollständigkeit hin erstellt - sie stehen lediglich als einige Beispiele.

(Die ERROR-Behandlung ist hier als Platzhalter zu verstehen)
Py::: 1. funktional zuverlässig, 2. Anfänger-lesbar, 3. Py-Konformität
ulipy
User
Beiträge: 83
Registriert: Mittwoch 17. November 2021, 21:42
Wohnort: Ba-Wü

Verzeihung, falschen Knopf für die Links verwendet und nicht richtig registriert...
Py::: 1. funktional zuverlässig, 2. Anfänger-lesbar, 3. Py-Konformität
Benutzeravatar
snafu
User
Beiträge: 6731
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Dass die Anzahl der Argumente den Modus (Lesen oder Schreiben) festlegt, erinnert eher an ein Kommandozeilen-Tool. Innerhalb von Python würde man dafür besser zwei entsprechende Funktionen schreiben. Damit entfallen auch die komischen Prüfungen und die if-Verzweigungen. Ich würde auch gar nicht das Setzen und Holen der Werte kapseln, sondern das Dict direkt liefern. Dann bleibt es bei load_config(filename, default=DEFAULT_CONFIG) und save_config(cfg, filename). Wobei DEFAULT_CONFIG auf Modulebene steht und genutzt wird, falls der angegebene Dateiname nicht existiert. Dann schrumpft das Ganze auf 2 Dreizeiler-Funktionen + Zeilen für die DEFAULT_CONFIG.
Benutzeravatar
sparrow
User
Beiträge: 4164
Registriert: Freitag 17. April 2009, 10:28

Funktionen sollten nach ihren Tätigkeiten benannt werden. Ich nehme an das "rw" steht für read/write? Warum ist as beides in einer Funktion? Das tut man so nicht.

Du lässt der Funktion eine beliebige Anzahl von Parametern übergeben nur um dann hinterher die Anzahl der Parameter zu prüfen?
Das kann weg. Python kennt benannte Parameter und für die auch noch Default-Werte. Hier weist du irgenwdelchen Parametern magisch Fähigkeiten und Bedeutung zu. Das tut man so nicht.

Dein data_path zeigt auf das aktuelle Arbeitsverzeichnis. Der denkbar schlechteste Platz für wiederzufindende Dateien, denn der kann bei jedem Aufruf anders sein. Entweder irgendwo ins User-Verzeichnis oder zumindest in das Verzeichnis in dem das Script liegt.
Was ist dir bei dem Namen für die Datei passiert? Hast du den mit der Handrückseite getippt?

Warum habe die Schlüssel führende Unterstriche? Weg.
Die Kommentare sind in dieser Form überflüssig. Faustformel: Kommentare im Code sollen erklären _warum_ etwas getan wird, nicht was getan wird. Das sollte der Code erklären.

Jetzt prüfst du nicht nur auf die Anzahl der Argumente - der Wert des ersten Arguments kann auch noch magisch etwas anderes Auslösen als man denkt. Macht man so nicht.

Ich sehe im Moment auch nicht, wo dein Code mehr Vorteil bietet als ein simples Vorgehen mit je einer Methode zum Lesen und Schreiben eines kompletten dicts. Aber ich sehe sehr viele Nachteile.

Edit: snafu war schneller 8)
Sirius3
User
Beiträge: 17710
Registriert: Sonntag 21. Oktober 2012, 17:20

Fehler meldet man per Exception an den Aufrufer zurückt, nicht per print und quit.
Jede Funktion sollte genau eine Aufgabe haben, und nicht drei.

Code: Alles auswählen

from pathlib import Path 
import json

SETTINGS_FILENAME = Path('dummy_f_dfg_ff__Y_TmP_mydata.json')

DEFAULTS = {
    'del_orphaned': False,   # if true:  del orphaned versions
    'demo_only': False,      # if true:  demo only
    'hide_versions': False,  # if true:  hide
    'symlinks_dirs': False,  # if false: ignore
    'symlinks_files': False, # if false: ignore
    # 'scan_all_subdirs', # visibility of subdirs for power-user
}


def read_settings():
    if not SETTINGS_FILENAME.exists():
        # read defaults
        return dict(DEFAULTS)
    else:
        # read from file
       return json.loads(SETTINGS_FILENAME.read_text())


def write_settings(data):
    SETTINGS_FILENAME.write_text(json.dumps(data))


def main():
    settings = read_settings()
    print(settings['demo_only'])
    settings['demo_only'] = True
    print(settings['demo_only'])
    write_settings(settings)

if __name__ == "__main__":
    main()
narpfel
User
Beiträge: 643
Registriert: Freitag 20. Oktober 2017, 16:10

Zusätzlich enthält das `if not SETTINGS_FILENAME.exists()` eine TOCTOU-Race-Condition, man sollte besser EAFP benutzen:

Code: Alles auswählen

def read_settings():
    try:
        contents = SETTINGS_FILE.read_text(encoding="utf-8")
    except FileNotFoundError:
        return dict(DEFAULTS)
    else:
        return json.loads(contents)
Es kann auch noch zusätzlich ein `PermissionError` auftreten, wenn die Datei existiert, aber nicht gelesen werden darf.

Außerdem sollte man beim Lesen und Schreiben von Dateien immer ein `encoding` angeben, weil man sonst das Defaultencoding des Systems (unter Windows `cp1252`) benutzt, JSON (und eigentlich alles andere auch) aber immer als UTF-8 kodiert sein sollte.
Benutzeravatar
__blackjack__
User
Beiträge: 13003
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

Ich würde die Datei gar nicht selbst lesen oder schreiben, sondern das `json`-Modul das erledigen lassen. Das hat dafür `load()` und `dump()` (ohne `s`), und wenn man die Datei im Binärmodus öffnet, kümmert es sich auch gleich selbst um die Kodierung. Beim schreiben UTF-8 und beim lesen erkennt es beliebige UTF-* am BOM falls vorhanden, oder eben UTF-8 falls nicht.
“Most people find the concept of programming obvious, but the doing impossible.” — Alan J. Perlis
Benutzeravatar
snafu
User
Beiträge: 6731
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Und das else kann bei den Codes der Vorposter auch entfallen, da sich in den Fällen der Programmfluss nicht ändern würde.
ulipy
User
Beiträge: 83
Registriert: Mittwoch 17. November 2021, 21:42
Wohnort: Ba-Wü

Danke für die hilfreichen Komentare!
Hier die für mich wichtigsten Stichwörter:

Nur zwei *args?
ja, die größten "Kopfschmerzen" bzw. "Bauchweh" lag auch auf meiner Seite bei der Verwendung von nur zwei *args!
Zuerst waren das drei, dann zwei, jetzt sind es wieder drei.
Das Motto "weniger ist besser" war ganz klar über das Ziel hinausgeschossen...

Nur eine Funktion / ein Objekt?
Ja, dabei wird es wohl bis auf Weiteres bleiben, vermute ich.
Der in diesem Fall m. E. letztlich überwiegende Vorteil ist der "Schutz" gegen Vergessslichkeit, "Schlamperei", Sucherei etc.

Lesbarkeit der Verzeweigungen:
Ja, durch die Verwendung von drei args ist das jetzt VIEL "schöner" umzusetzen, in mehrfacher Hinsicht ....

@__blackjack__
das Thema codecs ist leider ein SEHR tiefes, wie so viele andere auch...
Ich bin ausgegangen davon, dass Python3 (liegt heirr zu Grunde) utf-8 als default verwendet.
Auf die Möglichkeit, dass externe Module (hier json) dies anders sehen könnten, war ich bisher nicht gekommen :o - dies könnte jedoch der Fall sein - keine Ahnung..
An die Runde:
Wie verhält sich denn dieses?

Falls json diesen Python3-default berücksichtigt, wird für jeden vorkommenden Fall automatisch utf-8 verwendet - falls nicht, ist dieser natürlich in jedem Fall anzugeben :!:

So sieht das jetzt aus:

Code: Alles auswählen

import os
import json

# Meta-Bemerkungen (in deutscher Sprache) entfallen ab dem pre-release.
# Sie dienen bis dahin lediglich Kommentaren, welche zum leichteren Verständnis von "Merkwürdigkeiten" im Code dienen

# !access settings via this function only please!
def rw_settings(*args):
    """
    Read / write settings
    If no settings-file is found, use defaults
    
    *args:
      accepted are from 1 to 3 arguments

      args[0]:
        is defining the access-mode

        valid args[0]:
        - 'read_default_data'
          NO write operation is permitted

        - 'ro' (read only)
          return a dict-value
          EXCEPTION:
          in case no file for settings-data is found on disc,
          defaults initially are written to file
        
        - 'rw' (read write)
          case a, no (optional) third arg is available:
            return a value
          case b, a third arg is available:
            update a key-value and
            return this value
      
      args[1]:
        - represents a key only
      
      args[2]:
        - represents a value only
      
    Access samples:
    # sind hier noch veeeeeerkehrt angegeben .........................
    
    Read:
      rw_settings('ro', read_default_data')
      rw_settings('_symlinks_dirs')
    
    Write:
      rw_settings('_symlinks_dirs', 'True')
    """

    # no. of arguments: two or three only
    if 1 < len(args) > 3:
        
        # Implementation des error-handling ist temporär !!!

        print('!ERROR!   !ERROR!   !ERROR!')
        print('expected 1 or 2 args only, received:', len(args))
        quit()

    # Angabe des Arbeitsverzeichnisses und des Dateinamens ist temporär !!!
    # set path for settings-file
    data_path = '.\\dummy_f_dfg_ff__Y_TmP_mydata.json'

    # defaults for settings data
    data = {
        '_del_orphaned': False,   # if true:  del orphaned versions
        '_demo_only': False,      # if true:  demo only
        '_hide_versions': False,  # if true:  hide
        '_symlinks_dirs': False,  # if false: ignore
        '_symlinks_files': False, # if false: ignore
        # 'scan_all_subdirs', # visibility of subdirs for power-user
        }

    if args[0] == 'read_default_data':
        # return default dict
        return data

    elif args[0] == 'ro':
        # EXCEPTION:
        # in case no file is existing, create one, using default data
        if not os.path.exists(data_path):
            with open(data_path, 'w') as f:
               json.dump(data, f)

        # read settings from file
        with open(data_path, 'r') as f:
            data = json.load(f)

        return data[args[1]]

    elif args[0] == 'rw':
        # a third arg is expected
        # update key-value
        data[args[1]] = args[2]

        # write updated data to disc
        with open(data_path, 'w') as f:
           json.dump(data, f)

        return data[args[1]]

    else:
        print('!ERROR!   !ERROR!   !ERROR!')
        print('unknown arg received:', args[0])
        quit()

print("rw_settings('read_default_data'):")
print(rw_settings('read_default_data'))

print("rw_settings('ro', '_demo_only'):")
print(rw_settings('ro', '_demo_only'))

print("rw_settings('rw', '_demo_only', 'True'):")
print(rw_settings('rw', '_demo_only', 'True'))
Könnte das nach den Änderungen erst mal so stehen bleiben?
Benutzeravatar
sparrow
User
Beiträge: 4164
Registriert: Freitag 17. April 2009, 10:28

Nee, weil es schrecklich ist.
Es ignoriert halt alles, was zu deinem Code gesagt wurde. Sich mit diesem Thema zu beschäftigen ist also reine Zeitverschwendung.
Natürlich kannst du gegen die Progammiersprache programmieren und irgendwie außergewöhnlich schwer verständlichen Coden schreiben. Es ist dann halt aber außergewöhnlich schwer verständlicher Code und hat mit dem, was Python aus macht, nichts zu tun.

Eine gute Lösung für dein Problem wurde dir her im Thread bereits gezeigt. Ich sehe nicht, wo dein Code dem überlegen sein sollte. Ich sehe aber viele Argumente dagegen. Und auch die wurden hier schon alle benannt.
Benutzeravatar
snafu
User
Beiträge: 6731
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Also nach seinem letzten Beitrag hat er sich für mich stark trollverdächtig gemacht. Aber wer weiß. Hier tummeln sich ja öfter mal so schräge Vogel rum, die tatsächlich ernst meinen, was sie schreiben.
ulipy
User
Beiträge: 83
Registriert: Mittwoch 17. November 2021, 21:42
Wohnort: Ba-Wü

Vorneweg:
an die TOCTOU-Racecondition z. B. hatte ich zu dem Zeitpunkt einfach nicht gedacht

Wenn das hier so rauskommt tut mir das leid - "schräger Vogel" wäre dann im Vergleich die eher treffende Einschätzung.

Was mir das zeigt:
Die Energie, welche erforderlich wäre, "pythonische" Regeln und Stil einzuhalten, wird keine meiner Optionen sein. Das ist auf einer Ebene zwar schade - die Welt geht dadurch jedoch nicht unter. Wichtig ist, dass mir das klar bewusst ist.

Was folgt daraus?
Python als Werkzeug zur Umsetzung funktionaler anwendungssicherer Programme zu verwenden.

Das "Problem" Lesbarkeit hier auf dieser Ebene stammt mit Sicherheit aus dem Unterschied in der grundsätzlichen "Denke". Wenn jemand - wie praktisch alle hier - mit OOP "aufgewachsen" ist, erscheint die Lesbarkeit "schwierig". Im umgekehrten Fall, wenn jemand OOP nie gelernt oder angewandt hat, kann er mit dem Code hier einigermaßen sicher umgehen.

Ich bin/war(?) tatsächlich dankbar für die vielen Hilfen!
Py::: 1. funktional zuverlässig, 2. Anfänger-lesbar, 3. Py-Konformität
Benutzeravatar
sparrow
User
Beiträge: 4164
Registriert: Freitag 17. April 2009, 10:28

ulipy hat geschrieben: Donnerstag 9. Dezember 2021, 18:25Das "Problem" Lesbarkeit hier auf dieser Ebene stammt mit Sicherheit aus dem Unterschied in der grundsätzlichen "Denke". Wenn jemand - wie praktisch alle hier - mit OOP "aufgewachsen" ist, erscheint die Lesbarkeit "schwierig". Im umgekehrten Fall, wenn jemand OOP nie gelernt oder angewandt hat, kann er mit dem Code hier einigermaßen sicher umgehen.
Nö. Die Einschätzung ist falsch.
Mit Objektorientierung hat dein Code hier nichts zu tun.
Du versuchst hier Erklärungen für schlechten Stil zu finden - da ist aber keine.
Ich wiederhole mich: Wie es richtig, gut und simpel geht wurde hier ausreichend dargelegt. Ganz ohne Objektorientierung.
Was mir fehlt ist deine Erklärung warum deine Lösung mit dem magischen ersten Argument besser sein soll als korrekt benannte Funktionen.

Es sollte selbsterklärend sein, dass dem Leser (und das bist auch du bei deinem eigenen Code)

Code: Alles auswählen

def write_settings(...
eingängiger ist als

Code: Alles auswählen

def read_or_write_settings("write", ...
Eine Funktion hat eine Aufgabe. Nicht mehrere. Auch das wurde hier bereits gesagt. Es heißt übrigens "Funktion" wie in "funktionale Programmierung" nicht wie "Funktion" in "Objektorientierte Programmierung".

Als ich von Zeitverschwendung gesprochen habe, meinte ich übrigens eher die Leute, deren Beiträge zu deinem Code du hier ignorierst - nicht dicht.
Benutzeravatar
__blackjack__
User
Beiträge: 13003
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@ulipy: Ich glaube nicht das hier alle mit OOP ”aufgewachsen” sind. Ich zum Beispiel nicht. Und bei der letzten Fragestellung mit der Funktion die mehrere Sachen macht und als Schnittstelle dann ein total undurchsichtiges ``*args`` mit zwei oder drei Argumenten bekommt, hat die Kritik ja auch gar nichts mit OOP zu tun. Das eine Funktion in der Regel genau *eine* Sachen machen sollte und nicht in der Funktion mehrere, sich ausschliessende Pfade existieren sollten, ist etwas das vor 30 Jahren als ich in Pascal, QBasic, und C programmiert habe, schon galt. Da gab es manchmal Gründe Ausnahmen zu machen, die es heute nicht mehr gibt, weil Laufzeit und Speicherverbrauch heute weniger kritisch sind und man beispielsweise nicht mehr darauf achten muss, dass ein Codesegment in 64 KiB passen muss, oder es auch noch Rechner gibt die im einstelligen Mhz-Bereich getaktet sind.

Ausserdem ist OOP ein Paradigma und nicht eine Spracheigenschaft und wenn man OOP gelernt hat, wird man sicher auch APIs in prozeduralen Programmiersprachen ”finden”, die sich sehr objektorientiert anfühlen. Der Schritt in Pascal von RECORD + Prozeduren/Funktion und gelegentlichen Prozedur- und Funktionstypen zu OBJECT und Methoden ist auch kein wirklich grosser. Und diesen Schritt konnte man ja auch vor 30 Jahren schon gehen. Ich hatte den damals im ersten Anlauf nicht richtig verstanden, unter anderem weil ich den entscheidenden Unterschied nicht sah und das erst nur für einen reinen syntaktischen Unterschied wahrnahm eigentlich das gleich zu schreiben, was ich sowieso schon hatte. So richtig Klick gemacht hatte das dann erst Ende der 90er mit Java.
“Most people find the concept of programming obvious, but the doing impossible.” — Alan J. Perlis
Antworten