Diverse Syntax Problemchen..

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.
ulipy
User
Beiträge: 83
Registriert: Mittwoch 17. November 2021, 21:42
Wohnort: Ba-Wü

Hallo Foristi,
hatte nicht gedacht, dass die Arbeit an einem kleinen Programm trotz einiger Rumprobiererei so schnell wieder hängt und bin deshalb jetzt hierher auf einen eigenen thread 'umgezogen'.

Falls es mit der SuFu klappt, wird dies natürlich vorgezogen (war: viewtopic.php?p=396391#p396391

Habe es bisher nicht geschafft, als binär deklarierte "strings" mit == zu vergleichen. Da ich aus Laufzeitgründen beide Methoden benötige (vorrangig "Bordmittel", nachrangig exterrne Progs), bleibt das binäre Einlesen wegen codec Problemen erhalten.

gegeben z. b.:
string = b'irgendwas' (stammt aus einer Liste mit b'werten', die dennoch als lesbare Zeichen dargestellt werden auf dem Monitor)
getestet soll werden auf (oder eben ähnlich):
if string == b'irgendwas': tu was...
Das habe ich bisher trotz vieler Versuche nicht geschafft

Hoffe, die Angaben genügen, um das nachzuvollziehen.

Danke schon mal!
Py::: 1. funktional zuverlässig, 2. Anfänger-lesbar, 3. Py-Konformität
Benutzeravatar
__blackjack__
User
Beiträge: 13006
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@ulipy: Was heisst denn in diesem Zusammenhang „nicht geschafft“? Wenn bei einem Vergleich `False` heraus kommt, dann waren die beiden Operanden halt nicht gleich. Bei Zeichenketten vs. `bytes` bedeutet das entweder die beiden Operanden hatten unterschiedliche Typen, also `bytes`-Objekte mit `str`-Objekten vergleichen ergibt immer `False`.

Sollten beide Operanden nicht vom gleichen Typ gewesen sein, dann enthielten sie halt unterschiedliche Codepoints (`str`) oder Bytewerte (`bytes`).

Bei Zeichenketten können einem noch die unterschiedlichen Arten bestimmte Zeichen als Codepoints zu repräsentieren einen Streich spielen. Es gibt beispielsweise Dateisysteme die Umlaute als zwei Codepoints liefern, also einmal den Grundbuchstaben, und dann die Pünktchen, oder als ein Codepoint, wo beides „pre composed“ enthalten ist. In solchen Fällen muss man die Zeichenketten vorher noch normalisieren. Siehe das `unicode`-Modul in der Standardbibliothek.

Ansonsten wird auch gerne mal vergessen, das bei Daten aus Textdateien Zeilenende-Zeichen an den Zeilenenden sind.
“Most people find the concept of programming obvious, but the doing impossible.” — Alan J. Perlis
ulipy
User
Beiträge: 83
Registriert: Mittwoch 17. November 2021, 21:42
Wohnort: Ba-Wü

Ja, das ist eine gute Frage und viell. liegt es tatsächlich an der Ungleihheit obwohl ich diese auf verschiedenste Art und Weise versucht habe nachzuprüfen - kann schon mal falsch abbiegen..

Werde ein lauffähiges Beispiel hier einfügen - das löst sich dann vielleicht auf..
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ü

es war ein Komma innerrhalb der b'string,' - Repräsentation

Hatte es einfach nicht richtig gesehen.. :oops:
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 Foristi,
das Folgende hat nun nicht mehr viel mit Syntax als solcher zu tun, ist aber auch nicht so einfach googelbar, da es wohl bis in die "Philosophie" von Python als OOP hineinragt (in einem PEP wäre dies sicher zu finden).

Es wäre toll, wenn dies hier geklärt werden könnte:

Ich möchte erreichen, manche der wesentlichen Variablen(-Strukturen) uneingeschränkt "global", also für alle Funtionen les- und schreibbar zu machen - aus vielen Gründen.

Dazu ist mir erst mal nichts Besseres eingefallen, als eine Klasse ausschießlich für diesen Zweck zu definieren.

Jetzt ist Python in der Lage,- wie wohl andere OO-Sprachen auch - Variablen ohne weitere Deklaration "spontan" zu definieren und zu nutzen.

Selbst solche, die NICHT in der Klasse vordefiniert sind (verzeiht meine Sprache..).

Es "funktioniert" oft einfach, ohne dass man das nun versteht oder verstehen muss..

Zum Beispiel:

Code: Alles auswählen

class MajorData:
    """ hold major data (global scope) """

    a1_to_a2_filter_dirs  = []
    b1_to_b3_filter_files = []

    clean_filter_a1       = []  # extensions from A-SichtbarkeitVerzeichnisse.txt EIN
    clean_filter_a2       = []  # names from A-SichtbarkeitVerzeichnisse.txt AUS
    clean_filter_b1       = []  # file-extensions from B-SichtbarkeitDateien.txt
    clean_filter_b2       = []  # file-names from B-SichtbarkeitDateien.txt
    clean_filter_b3       = []  # full pathnames from B-SichtbarkeitDateien.txt

    disc_list_preselected = []  # listed items according to selection filters
    disc_list_zkos        = []  # list of files zko.*
    
    # following items may be moved to a separate class
    dirs_cnt              = []
    files_cnt             = []
mit
x = MajorData() und
x.eine_spontan_definierte_variable = 'sooo einfach'

kann man mit
print(x.eine_spontan_definierte_variable)

=> "sooo einfach" ausgeben

Nun die eigentliche Frage:
Brauch ich denn die oben in der Klasse vordefinierten Variablennamen überhaupt?
Oder dienen die nur der Programmier-Disziplin?
Oder seh ich das Ganze komplett verkehrt?

Würde mich riesig freuen, wenn es dazu etwas Erläuterung gäbe!
Py::: 1. funktional zuverlässig, 2. Anfänger-lesbar, 3. Py-Konformität
Sirius3
User
Beiträge: 17712
Registriert: Sonntag 21. Oktober 2012, 17:20

Du siehst es komplett verkehrt. Mit globalen Variablen handelst Du Dir viele Probleme ein. Ein Programm wird unverständlich, nicht testbar, ist nicht modular, skaliert nicht und und und.
Genauso verhält es sich mit Attributen, die irgendwo angelegt werden. Es ist nicht mehr nachvollziehbar, wann welche Instanz welche Attribute hat, was zu schwer zu findenden Fehlern führt. Deshalb müssen alle Attribute in der __init__-Methode angelegt werden.
Benutzeravatar
__blackjack__
User
Beiträge: 13006
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@ulipy: Du willst keine globalen Variablen haben. Egal wieviele Gründe Dir einfallen das doch haben zu wollen, das willst Du nicht.

Und Du definierst da Klassenvariablen — das sind globalen Variablen, die man nicht haben will. Und dann erstellst Du noch ein Exemplar von dieser Klasse nur um da dynamisch ein Attribut dran zu pappen, das dann aber nicht global ist, sondern nur auf diesem `x` existiert. Aber über das `x` gibt es jetzt plötzlich noch einen Weg um an die globalen Daten heran zu kommen, wobei sich dann veränderbare und nicht veränderbare Attribute subtil anders verhalten wenn Du die über `x` ”änderst”, denn das jeweilige Objekt verändern ist dann global sichtbar — Zuweisungen aber nur auf *dem* `x` und nicht in der Klasse, weil Zuweisungen auf dem Objekt Instanzattribute erstellen. Verwirrender geht's kaum.

Auf Klassen definiert man nur Konstanten, weil es sonst globale Variablen wären, und alle Attribute auf dem Objekt sollten nach Ablauf der `__init__()` vorhanden sein, und das Objekt sollte in einem benutzbaren Zustand sein.

Was auch schon böses ahnen lässt sind die komischen generischen und nummerierten Namen mit den erklärenden Kommentaren. Und wenn ich die richtig lese, scheinen mindestens ein paar von den Listen Elemente zu enthalten die eigentlich zusammengehören. Die sollten dann aber nicht in verschiedene Listen verteilt werden, sondern zusammen in einer. Und falls da Redundanzen sind, sollte man sich die auch sparen. Also beispielsweise den vollen Pfadnamen und die Dateinamenserweiterung: `pathlib.Path`-Objekte. Wenn man die Erweiterung braucht, fragt man die einfach per `suffix`-Attribut ab.
“Most people find the concept of programming obvious, but the doing impossible.” — Alan J. Perlis
ulipy
User
Beiträge: 83
Registriert: Mittwoch 17. November 2021, 21:42
Wohnort: Ba-Wü

@blackjack
zuerst: hoffe, dass die von meiner Seite bewusst angelegte pythonische "Bombe" nicht missverständlich "gelegt" war..

Nochmals zur Sache @Sirius, @blackjack
- Vieles hat sich durch eure Beiträge sowohl aufgeklärt als auch bestätigt - großen Dank dafür!

Also:
- globale Variablen sind für mich eher ein (dann *sehr* diszipliniert zu behandelnder) "workaround" als ein Wunsch

- ich muss leider mit eher "naiven" Programmiermethoden klarkommen, um überhaupt zu einem Ergebnis zu kommen - das "Ergebnis" ist hier schon das Ziel erster Priorität

- was sich mir überhaupt nicht erschließt ist: weshalb zeigt mir der Parser nicht sofort die rote Karte?

- das Anlegen in der `__init__() - Methode ist auf jeden Fall grundsätzlich verstanden

- die Aufteilung in verschiedene Listen hat nur wenig Redundanz - das erschließt sich erst auf der semantischen Ebene (führt hier momentan zu "weit")

- mir ist (leider) noch unklar, wie ich bei aktuellem Kenntnisstand am sinnvollsten, praktisch, mit Listen dynamisch umgehen kann

Ich möchte also gerne eine Handvoll Listen mit langen Namen haben (u. a. auch wegen Lesbarkeit für mich selbst..), deren Werte innerhalb einiger Funktionen verändert UND ohne den Zwang zu einem:

Code: Alles auswählen

... ...
    return so_ein_langer_name_nochmal1, so_ein_langer_name_nochmal2, so_ein_langer_name_nochmal3, so_ein_langer_name_nochmal4, so_ein_langer_name_nochmal5
oder auch:

Code: Alles auswählen

... ...
    return \
        so_ein_langer_name_nochmal1,  \
        so_ein_langer_name_nochmal2,  \
        so_ein_langer_name_nochmal3,  \
        so_ein_langer_name_nochmal4, \
        so_ein_langer_name_nochmal5
schreiben zu müssen.

Hab momentan keine Idee, wie das unter diesen Bedingungen am Besten erreicht werden könnte..
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ü

der Weisheit letzter Schluss: werde verm. damit leben müssen..
Py::: 1. funktional zuverlässig, 2. Anfänger-lesbar, 3. Py-Konformität
__deets__
User
Beiträge: 14494
Registriert: Mittwoch 14. Oktober 2015, 14:29

Diese ganze Rum-Meta-Rei bringt nichts. Entweder zeigst du wirklich realen Code, und erklaerst, was dein zu loesendes Problem. Oder man kann eben nur im allgemeinen bleiben, und da gilt: globaler Zustand ist aus gutem Grund verpoent, und die hier ueblichen Verdaechtigen schaffen es, auch bei komplizierten Aufgabenstellungen, darauf zu verzichten. Das Problem ist also nicht dein Problem. Sondern deine Herangehensweise.
Benutzeravatar
__blackjack__
User
Beiträge: 13006
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@ulipy: Der Parser meckert nicht, weil das syntaktisch korrekt ist. Ansonsten verhindert Python nicht das man ganz furchtbaren Code schreibt. Versucht es noch nicht einmal. Python geht vom mündigen Programmierer aus, der weiss was er tut. Sprachen die den Programmierer mehr ”gängeln”, wie beispielsweise Java, können ja trotzdem nicht verhindern, das man ganz furchtbaren Code schreibt. Denn „keine globalen Variablen“ ist im Grunde eine sprachunabhängige Richtlinie — ausgenommen die Programmiersprachen bei denen man das nicht anders machen kann, weil sie keine, oder nicht ausreichend, lokale Namensräume bieten. Und in ein paar Sonderfällen, zum Beispiel Plattformen mit extrem limitierten Ressourcen (Speicher, Rechenleistung, Stackgrösse, …).

Die üblichen IDEs/Linter für Python werden darauf hinweisen, dass die Klasse keine Klasse ist, weil sie keine Methoden hat, und falls es so einfach wie mit dem `x` ist, werden die auch mit statischer Analyse erkennen, dass da ein Attribut ”von aussen” eingeführt wird. Beispiel für Dein Beispiel:

Code: Alles auswählen

forum19.py:3:0: R0903: Too few public methods (0/2) (too-few-public-methods)
forum19.py:26:4: W0201: Attribute 'eine_spontan_definierte_variable' defined outside __init__ (attribute-defined-outside-init)
Wenn man immer die gleichen Werte, von der Bedeutung her, zusammen als Argumente übergibt, und/oder als Rückgabewerte hat, überlegt man üblicherweise was man davon sinnvoll als Objekt(e) zusammenfassen kann. Falls man Funktionen hat die Objekte verändern, statt neue zu erstellen, sind das oft Kandidaten für Methoden.
“Most people find the concept of programming obvious, but the doing impossible.” — Alan J. Perlis
ulipy
User
Beiträge: 83
Registriert: Mittwoch 17. November 2021, 21:42
Wohnort: Ba-Wü

Ok, hab viel gelernt und nun einiges an Stoff für die nächsten Schrittchen im Gepäck.

@__deets__:
Ein grundsätzliches Verständnis brauch ich halt auf beiden Ebenen, um mich damit auch "wohlfühlen" zu können (Meta und Umsetzung) - es bringt m. E. momentan nichts, größere Stücke code zur Klärung von aktuellen Hindernisssen zu verwenden.

Vielen Dank nochmals!
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,
oh je, oh je, oh je, kann ich nur sagen...

Bin *inmitten* des Sprungs über das Stöckchen "OOP" und sehe nicht nicht mal eine Stelle zum auftreffen am Boden - die Lernkurve ist seeeeehr viel steiler als bei prozeduralem Ansatz.

Welche Art Objekt wäre das "richtige" für settings?

Settings:
- können einfach in einem dictionary oder json Datei gehalten werden
- werden beim allerersten Aufruf initiiert (wird umgehend in die json geschrieben)
- jeder val-Wert kann durch den Benutzer geändert werden (wird umgehend in die json geschrieben)
- jeder val-Wert soll le nach Bedarf im Programmlauf gelesen werden können

Möchte ich dafür nun eine Klasse? Dagegen spräche: es gibt nur eine einzige Instanz.

Mit einer Funktion hätte ich natürlich weniger Probleme, wenn das pythonisch gesehen "korrekt" ist?

Bin über jede Hilfe dankbar!
Py::: 1. funktional zuverlässig, 2. Anfänger-lesbar, 3. Py-Konformität
Benutzeravatar
__blackjack__
User
Beiträge: 13006
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@ulipy: Nur ein Objekt von einem Typen zu erstellen ist genau so wenig ein Grund gegen eine Klasse wie es das beim Prozeduralen Ansatz ein Grund gegen einen `struct`- oder RECORD-Typ ist.

Einstellungen kann man in einem Wörterbuch halten und Funktionen zum (de)serialisieren/persistieren auf einem Datenträger schreiben.

OOP in Python ist ja nicht wie in Java wo man alles zwanghaft in Klassen stecken muss.

Gegen Wörterbucher spricht, wenn die immer einen festen Satz an Schlüsseln haben. Denn dann missbraucht man die im Grunde als Objekt-Ersatz. Das kann in Fällen Ok sein, wo man beispielsweise das JSON aus einer API-Anfrage in eine andere Struktur bringt um es an eine andere API zu verfüttern, aber wenn da innerhalb des eigenen Programms ohne Not dauernd irgendwelche anonymen Blobs durch die Gegend gereicht werden, wird es schnell sehr unübersichtlich.

Der Übergang von prozedural zu OOP muss in Python auch nicht so krass wie beispielsweise in Java sein. Ein guter Startpunkt ist einfach erst einmal prozedural anzufangen, aber eben so wie man das in prozeduralen Sprachen auch macht. Denn auch dort hat man ja keine globalen Variablen, sondern reicht immer alles herum und fasst dazu Werte in Verbundtypen wie `struct` oder RECORD zusammen. Das ist in Python eben die Klasse. Sozusagen ein Verbuntdatentyp+. So hat sich das in prozeduralen Sprachen ja auch entwickelt, dass die mit OOP meistens damit angefangen haben an ein `struct` oder RECORD neben den Datenfeldern um Methoden zu erweitern.
“Most people find the concept of programming obvious, but the doing impossible.” — Alan J. Perlis
rogerb
User
Beiträge: 878
Registriert: Dienstag 26. November 2019, 23:24

Ich bin der Meinung, dass die Unterschiede bei der Anforderung - "Settings in einer geeigneten Datenstruktur ablegen" - zwischen einem Dictionary und einer Datenklasse verschwindend gering sind.
Besonders, wenn man sich überlegt, dass Klasseninstanzen ihre Daten intern in einem Dictionary ablegen, fällt der Unterschied kaum auf.

Code: Alles auswählen

from dataclasses import dataclass
from enum import Enum, auto


class Option(Enum):
    STRONG = auto
    MEDIUM = auto
    LIGHT = auto


@dataclass
class Settings:
    setting_a: int
    setting_b: str
    setting_c: list
    setting_d: Option


settings1 = Settings(
    setting_a=7,
    setting_b="b",
    setting_c=["front", "back", "left", "right"],
    setting_d=Option.MEDIUM,
)

settings2 = {
    "setting_a": 7,
    "setting_b": "b",
    "setting_c": ["front", "back", "left", "right"],
    "setting_d": Option.MEDIUM,
}


print(settings1.__dict__)
print(settings2)

"""
Ausgabe:
{'setting_a': 7, 'setting_b': 'b', 'setting_c': ['front', 'back', 'left', 'right'], 'setting_d': <Option.STRONG: <class 'enum.auto'>>}
{'setting_a': 7, 'setting_b': 'b', 'setting_c': ['front', 'back', 'left', 'right'], 'setting_d': <Option.STRONG: <class 'enum.auto'>>}
"""
Es müssten also weitere Anforderungen definiert werden um sich zu entscheiden.
Benutzeravatar
__blackjack__
User
Beiträge: 13006
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@rogerb: Naja, der Zugriff ist bei der Datenklasse schon mal schöner und die Ausgabe des *eigentlichen* Objekts verrät, dass es sich um `Settings` handelt. Auf das `__dict__` greift man nicht direkt zu, das muss ein Objekt ja auch gar nicht zwingend haben.
“Most people find the concept of programming obvious, but the doing impossible.” — Alan J. Perlis
ulipy
User
Beiträge: 83
Registriert: Mittwoch 17. November 2021, 21:42
Wohnort: Ba-Wü

das alles ist bereits einiger "Tobak" für mich, obwohl aus Python-Sicht sicherlich in keiner Weise "komplex".

Mit einer Umsetzung jedenfalls haperts immer noch gewaltig:

Code: Alles auswählen

import os
import json

# del prior to initial testing
os.system('del .settings.json')

# create settings
class Settings:
    """
    hold settings data in class
    could the below be a minimalistic form?
    greater functionality is not required
    """

    settings_dict = []

    def __init__(self):
        # system setting
        # set to zero if call is 'virgin' call
        # is never changed
        self.settings_dict['main_call_count': 0]
        
        # default user settings
        self.settings_dict['del_orphaned': False]   # if true:  del
        self.settings_dict['demo_only': False]        # if true:  demo only
        self.settings_dict['hide_versions': False]   # if true:  hide
        self.settings_dict['symlinks_dirs': False]   # if false: ignore
        self.settings_dict['symlinks_files': False]  # if false: ignore

print(Settings)
print()

print(Settings.settings_dict)

x = Settings
print(x.settings_dict)

# dict is remaining empty "[]" in created class and in instance

x.settings_dict['main_call_count'] = 0
print(x.settings_dict['main_call_count'])
# ERROR ... so gehts also nicht...
Ein über eine Klasse etwas "gesichertes" dictionary wäre schon seeehr fein und ausreichend.

Gelesen und geschrieben würden dann einzelne items des dict eben auf ähnliche Art wie im Code.
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ü

oh, viell. find ichs doch noch moment..
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 - nee, das dict bleibt ja leer...
Py::: 1. funktional zuverlässig, 2. Anfänger-lesbar, 3. Py-Konformität
rogerb
User
Beiträge: 878
Registriert: Dienstag 26. November 2019, 23:24

@ulipy,

worauf möchtest du eigentlich hinaus? Wo läge der Vorteil, wenn man innerhalb der Klasse einen Dictionary anlegt um die Settings zu speichern?
Was spricht gegen einfache Klassenattribute? Was spricht gegen einen simplen alleinstehenden Dictionary?
Machst du es dir vielleicht unnötig kompliziert?
Antworten