Problem bei Wertübergabe in Funktion

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.
Nobuddy
User
Beiträge: 997
Registriert: Montag 30. Januar 2012, 16:38

Hallo zusammen,

mein Konstrukt ist folgendes:

Code: Alles auswählen

my_reader = partial(csv.reader, delimiter='\t', quotechar='^')

def get_inhalt(filename, beschreibung, ve, inhalt):

    # Überprüfung, ob Text vorhanden
    # Wenn ja, Ausgabe der numerischen Werte
    def find_digits(text):
        try:
            return re.search(regexp, text).groupdict()
        except AttributeError:
            return None


    suchmuster = list()
    with open(liste_inhalt_regexp_path, 'r') as infile:
        for r in my_reader(infile):
            suchmuster.append(r)


    daten = []
    with open(filename, "r") as infile:
        for r in my_reader(infile):
            for i in suchmuster:
                # Verarbeitung von Inhaltsangaben
                # RegExp
                regexp = re.compile(string.join(i), re.U|re.I)
                # Überprüfe, ob in Spalte beschreibung eine Inhaltsangabe enthalten ist
                # Wenn a Wert enthält
                # verarbeite diesen Wert
                if find_digits(r[beschreibung]) and r[ve] == 'VE' and r[inhalt] == '1':
                    a = find_digits(r[beschreibung])
                    print(a)
                    b = a.items()
                    c = b[0][1]
                    d = b[1][1]
                    # Verarbeite Werte, die nicht
                    # dem Muster von d entsprechen
                    if c != '' and c != '1':
                        c = re.sub('\.', '', c)
                        # Ersetze die Werte für inhalt und ve
                        r[inhalt] = c
                        r[ve] = 'VE'
                        # Füge die Zeilen in die Liste daten ein
                        daten.append(tuple(r))
                        break
                    else:
                        r[inhalt] = '1'
                        daten.append(tuple(r))
                        break
                else:
                    daten.append(tuple(r))
                    break

    if len(daten) > 0:
        daten = sorted(set(daten))
        write_csv(filename, daten)
In der Zeile von 'regexp = re.compile(string.join(i), re.U|re.I)' liegt mein Problem.
Hier versuche ich mit 'string.join(i)', Werte aus einer Liste zu nutzen.
Leider funktioniert dies so einfach nicht.

Wenn ich statt 'string.join(i)' den Wert direkt eingebe, z.B.:

Code: Alles auswählen

regexp = re.compile(r"INHALT: ?(?P<VALUE>\d*\.?\d*).?ST\s*(?P<UNIT>\w*)", re.U|re.I)
funktioniert das Konstrukt.

Hoffe Ihr könnt mir sagen, warum dies so nicht funktioniert und wie ich die Werte aus der Liste nutzen kann?

Grüße nobuddy
Zuletzt geändert von Nobuddy am Dienstag 24. April 2012, 16:29, insgesamt 2-mal geändert.
webspider
User
Beiträge: 485
Registriert: Sonntag 19. Juni 2011, 13:41

Um tatsächlich ``string.join(list)`` zu nutzen, müsstest du zuerst das string-Modul importieren. Da aber seit geraumer Zeit seine Methoden mittlerweile Methoden jedes gewöhnlichen Strings sind, reicht ein ``"".join(list)`` aus. Die andere Sache ist, dass join nur Sinn ergibt für Listen. Es sieht aber mehr danach aus als würdest du ihm einen String übergeben (zumindest sollte dein Suchmuster einer sein, ob es das auch wirklich ist, kann ich nur mutmaßen), was den Aufruf dieser Methode in deinem Fall relativ sinnlos macht.
Nobuddy
User
Beiträge: 997
Registriert: Montag 30. Januar 2012, 16:38

Ja, das ist richtig, die Werte in der Liste sind strings.

Code: Alles auswählen

r"INHALT: ?(?P<VALUE>\d*\.?\d*).?ST\s*(?P<UNIT>\w*)"
Gibt es da vielleicht eine andere Möglichkeit, dies so nutzen zu können?
webspider
User
Beiträge: 485
Registriert: Sonntag 19. Juni 2011, 13:41

Captain Obvious sagt mir, dass wenn du den Wert des Suchmusters übergeben kannst, du auch einfach seinen Namen nutzen kannst. Also statt ``regexp = re.compile(string.join(i), re.U|re.I)``dann ``regexp = re.compile(i, re.U|re.I)``. Oder übersehe ich da eine Feinheit in deinem Code?
Nobuddy
User
Beiträge: 997
Registriert: Montag 30. Januar 2012, 16:38

Das habe ich als erstes versucht, hat aber nicht funktioniert.
Dachte, daß die Werte der Liste so

Code: Alles auswählen

['r"INHALT: ?(?P<VALUE>\d*\.?\d*).?ST\s*(?P<UNIT>\w*)"']
ausgegeben werden und daher dies nicht funktionieren würde. Daher habe ich es dann mit 'string.join(liste)' versucht.
webspider
User
Beiträge: 485
Registriert: Sonntag 19. Juni 2011, 13:41

Ich befürchte, dass die Inhalte der Suchmuster-Liste keine Raw-Strings sind.
Nobuddy
User
Beiträge: 997
Registriert: Montag 30. Januar 2012, 16:38

Hm, evtl. eine Idee wie ich das Problem lösen könnte?
BlackJack

@Nobuddy: Gar nicht erst so sinnlose Datenstrukturen wie Listen mit einem Element das eine `repr()`-Darstellung einer Zeichenkette ist, erstellen. Die Frage dabei ist doch wie das überhaupt zustande gekommen ist‽
Nobuddy
User
Beiträge: 997
Registriert: Montag 30. Januar 2012, 16:38

Vorher hatte ich ca. 10 mal diese Konstrukt hintereinander, mit den jeweiligen verschiedenen Werten.
Ich habe zuerst gedacht, dies wäre eine gute Idee, das Ganze in eine einzige Funktion zu packen und die regex-Ausdrücke in eine Datei zu packen und diese dann dort abzurufen.

Vielleicht hast Du mir einen Vorschlag?
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

Wie sieht denn Dein Format für das Speichern eines RegExp aus?
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
Nobuddy
User
Beiträge: 997
Registriert: Montag 30. Januar 2012, 16:38

So z.B.:

Code: Alles auswählen

r"INHALT: ?(?P<VALUE>\d*\.?\d*).?BL\s*(?P<UNIT>\w*)"
r"INHALT: ?(?P<VALUE>\d*\.?\d*).?ET\s*(?P<UNIT>\w*)"
r"INHALT: ?(?P<VALUE>\d*\.?\d*).?ST\s*(?P<UNIT>\w*)"
Zuletzt geändert von Hyperion am Dienstag 24. April 2012, 18:12, insgesamt 1-mal geändert.
Grund: Code-Blöcke machen hier mehr Sinn als Listen ;-)
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

Na das sieht ja nach Python aus ;-) Das kannst Du so natürlich nicht direkt einlesen und dann erwarten auf "magische" Art und Weise Raw-Strings zu bekommen. (Zudem ist hier das `csv`-Modul fehl am Platze!)

Du könntest das tatsächlich in eine Python-Datei umwandeln und diese dann per `import` in Dein Script einbetten, wenn es denn Raw-Strings sein müssen. Du musst Die Liste dann natürlich drum herum bauen.

Edit: Unterscheiden die sich alle nur durch diese beiden Buchstaben in der Mitte? Wenn ja, dann kannst Du daraus doch einfach *einen* RegExp machen:

Code: Alles auswählen

r"INHALT: ?(?P<VALUE>\d*\.?\d*).?(BL|ET|ST)\s*(?P<UNIT>\w*)"
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
Nobuddy
User
Beiträge: 997
Registriert: Montag 30. Januar 2012, 16:38

Bin jetzt auf eine einfache Lösung gekommen, die für mich auch übersichtlich erscheint und ich keine zweite Datei für die RegExp benötige.

Code: Alles auswählen

from b_test import get_inhalt
get_inhalt(base_daten_path, 3, 6, 7, r"INHALT: ?(?P<VALUE>\d*\.?\d*).?ST\s*(?P<UNIT>\w*)")  # suche nach 'INHALT: [Zahlenwert] ST' (Stück)
get_inhalt(base_daten_path, 3, 6, 7, r"INHALT: ?(?P<VALUE>\d*\.?\d*).?ET\s*(?P<UNIT>\w*)")  # suche nach 'INHALT: [Zahlenwert] ET' (Etiketten)
get_inhalt(base_daten_path, 3, 6, 7, r"INHALT: ?(?P<VALUE>\d*\.?\d*).?BL\s*(?P<UNIT>\w*)")  # suche nach 'INHALT: [Zahlenwert] BL' (Blatt)
Dein Vorschlag wäre mir lieber und einfacher, aber die Muster müssen einzeln durchlaufen, da es vorkommen kann daß evtl. mehr als nur ein Treffer vorhanden ist. Daher nehme ich zuerst ST dann ET und als letztes BL.

Es wird bei Etiketten manchmal zwei Werte angegeben, die ich multiplizieren sollte.
Beispiel: 'ETIKETTEN .... BLABLA.... INHALT: 5 BLATT a`3 ETIKETTEN'
Hier wäre die richtige Inhaltsangabe '15'. Aber da ist mir noch keine Lösung eingefallen.

Das restliche Konstrukt, deute ich nur grob an, da der Rest klar sein sollte.

Code: Alles auswählen

def get_inhalt(filename, beschreibung, ve, inhalt, suchmuster):

    # Überprüfung, ob Text vorhanden
    # Wenn ja, Ausgabe der numerischen Werte
    def find_digits(text):
        try:
            return re.search(regexp, text).groupdict()
        except AttributeError:
            return None


    daten = []
    with open(filename, "r") as infile:
        for r in my_reader(infile):
            # Verarbeitung von Inhaltsangaben
            # RegExp
            regexp = re.compile(suchmuster, re.U|re.I)
            # Überprüfe, ob in Spalte beschreibung eine Inhaltsangabe enthalten ist
            # Wenn a Wert enthält
            # verarbeite diesen Wert
            if find_digits(r[beschreibung]) and r[ve] == 'VE' and r[inhalt] == '1':
                a = find_digits(r[beschreibung])
...
..
BlackJack

@Nobuddy: Ich habe mir gerade noch einmal den Quelltext im ersten Beitrag angeschaut. Dass Deine Programme funktionieren ist ja eher so etwas wie ein Lottogewinn. :twisted: Du machst ziemlich wirre, unsinnige Sachen. Du hast eine Datei mit einem Regulären Ausdruck pro Zeile, liest die aber mit einer Funktion ein, die CSV-Daten mit Tab als Trennzeichen in verschachtelte Listen umsetzt. Das ist ja schon mal völlig unsinnig.

Dann gehst Du in einer Schleife die Muster durch, aber die Schleife wird *in jedem Fall* im ersten Durchlauf durch ein ``break`` abgebrochen — WTF‽ Ebenfalls in jedem Zweig wird am Ende `r` den `daten` hinzugefügt. Da würde es auch genügen wenn man das *einmal* an die passende Stelle schreibt.

Die regulären Ausdrücke in der innersten Schleife immer wieder aufs neue zu kompilieren, könnte man sich sparen. Entweder macht man das an einer geeigneten Stelle *einmal* pro Ausdruck, oder man lässt das kompilieren weg. Die Ausdrücke sollte man ausserdem an `find_digits()` als Argument übergeben, dann ist das weniger magisch und verwirrend.

Wenn man den Gruppen in einem regulären Ausdruck schon Namen gibt und sich das Ergebnis als Wörterbuch geben lässt, sollte man diesen Umstand auch nutzen um verständlicheren Quelltext zu schreiben und nicht dann doch wieder alles in eine Liste umwandeln und mit nichtssagenden Indexen hantieren. Wobei hier wieder nur reines Glück im Spiel ist, wenn der Code das macht was er soll, denn Wörterbücher sind ungeordnet. Welcher Wert jeweils an `c` und `d` gebunden wird, ist letztendlich Zufall. (`d` wird auch gar nicht verwendet‽)

Solche einbuchstabigen Namen sollte man sowieso nicht verwenden wenn der Gültikgeitsbereich nicht extrem klein ist („list comprehensions”, Generator-Ausdrücke, anonyme Funktionen, …), oder es sich nicht um offensichtliche Namen handelt, wie zum Beispiel `i` für eine ganzahlige Schleifenvariable. Womit `i` in diesem Fall schlecht gewählt ist, weil die meisten Leser eben erwarten, dass an *den* Namen, insbesondere in einer Schleife, ganze Zahlen gebunden werden, und keine Listen.

`re.sub()` zum ersetzen einer statischen Zeichenkette durch eine ander ist etwas überdimensioniert.
Nobuddy
User
Beiträge: 997
Registriert: Montag 30. Januar 2012, 16:38

Hallo BlackJack,

ja da war einiges unsinniges dabei, was ich jetzt behoben habe.
Auch habe ich manches kompakter gestaltet.

Code: Alles auswählen

def get_inhalt(filename, beschreibung, ve, inhalt, suchmuster):

    # Überprüfung, ob Text vorhanden
    # Wenn ja, Ausgabe der numerischen Werte
    def find_digits(text):
        try:
            return re.search(regexp, text).groupdict()
        except AttributeError:
            return None


    wert = 0
    daten = list()
    with open(filename, "r") as infile:
        for r in my_reader(infile):
            if r[ve] == 'VE' and r[inhalt] == '1':
                # Verarbeitung von Inhaltsangaben
                # RegExp
                regexp = re.compile(suchmuster, re.U|re.I)
                # Überprüfe, ob in Spalte beschreibung eine Inhaltsangabe enthalten ist
                if find_digits(r[beschreibung]):
                    zahlenwert = find_digits(r[beschreibung]).items()[0][1]
                    if zahlenwert != '' and zahlenwert != '1':
                        # Entferne 1.000 Trennzeichen
                        r[inhalt] = re.sub('\.', '', zahlenwert)
                        daten.append(tuple(r))
                        wert += 1
                    else:
                        r[inhalt] = '1'
                        daten.append(tuple(r))
                else:
                    daten.append(tuple(r))
            else:
                daten.append(tuple(r))

    if wert > 0:
        daten = sorted(set(daten))
        write_csv(filename, daten)
BlackJack hat geschrieben: Die regulären Ausdrücke in der innersten Schleife immer wieder aufs neue zu kompilieren, könnte man sich sparen. Entweder macht man das an einer geeigneten Stelle *einmal* pro Ausdruck, oder man lässt das kompilieren weg. Die Ausdrücke sollte man ausserdem an `find_digits()` als Argument übergeben, dann ist das weniger magisch und verwirrend.
Bin mir jetzt nicht im Klaren, wie Du das meinst. Hast Du mir evtl ein Beispiel?
BlackJack hat geschrieben:Wenn man den Gruppen in einem regulären Ausdruck schon Namen gibt und sich das Ergebnis als Wörterbuch geben lässt, sollte man diesen Umstand auch nutzen um verständlicheren Quelltext zu schreiben und nicht dann doch wieder alles in eine Liste umwandeln und mit nichtssagenden Indexen hantieren.
Da würde mich ein kurzes Beispiel interessieren, wie Du das meinst!
BlackJack

@Nobuddy: Überlege Dir mal wie oft Du `re.compile()` mit immer wieder dem selben regulären Ausdruck aufrufst. Da kommt doch bei dem gleichen Ausdruck auch immer wieder ein äquivalentes Objekt als Ergebnis. Also ist es unnötig das ständig aufs neue zu berechnen. Das sollte man *einmal* machen und dann das Ergebnis davon verwenden. Und dann vielleicht auch in `find_digits()` direkt die `search()`-Methode auf dem Objekt aufrufen statt `re.search()` zu verwenden. Das macht ja letztendlich auch nichts anderes als seinerseits dann noch mal die Methode auf dem Objekt aufzurufen. Diese Indirektion kann man sich sparen.

In `find_digits()` verwendest Du `regexp` ohne das man einfach nachvollziehen kann, wo der Wert dafür eigentlich her kommt. Man muss die komplette `get_inhalt()`-Funktion verstehen um zu sehen wo und wie der Name dort an einen oder mehrere Werte gebunden wird. Deshalb würde ich den regulären Ausdruck dort als Argument übergeben.

Die Funktion finde ich aber sowieso etwas übertrieben. Wenn man das „inline” schreibt und statt der Behandlung des `AttributError` das Ergebnis der Suche an einen Namen bindet und damit dann nur weiter macht wenn das Ergebnis nicht `None` ist, kann man das ganze kürzer schreiben und sich auch den unnötigen doppelten Aufruf von `find_digits()` sparen.

Zu den Gruppennamen: Schau Dir doch bitte mal an was das Wörterbuch enthält. Ein Wörterbuch in eine Liste mit Tupeln aus Schlüssel/Wert-Paare umzuwandeln um dann per verschachtelten Indexzugriff auf einen Wert zuzugreifen ist umständlich und wie gesagt auch *falsch*! Wenn das bei Dir funktioniert, dann ist das reiner Zufall, denn Wörterbücher haben keine Ordnung. Du fragst mit Deinem Code *irgendeinen* zufälligen Wert ab. Das würde nur funktionieren wenn das Wörterbuch nur einen Wert enthalten würde, aber dann wäre die Datenstruktur und der umständliche Zugriff noch unsinniger.

Der Schleifenkörper ist immer noch viel zu aufgebläht. Wenn etwas am Anfang oder Ende von *jedem* möglichen Zweig passiert, dann muss man das nicht in *jeden* Zweig reinschreiben, sondern *einmal* an passender Stelle. ``daten.append(tuple(r))`` wird in jedem Fall (fast) am Ende der Ausführung eines Schleifendurchlaufs gemacht. Das kann man deshalb auch *einmal* am Ende der Schleife machen. Damit sparst Du zwei ``else``-Zweige. Genau so kann man das erhöhen von `wert` aus dem ``if``/``else`` heraus ziehen. Und von dem Konstrukt bleibt auch nur noch das ``if`` wenn man mal überlegt was denn schlimmes passiert wenn man bei der '1' Tausenderzeichen entfernt.

`wert` ist übrigens ein ziemlich schlechter Name, weil nichtssagend. Denn ein Wert ist letztendlich *alles* was man an einen Namen binden kann. Namen sollten beschreiben wofür der daran gebundene Wert steht. In diesem Fall zum Beispiel scheint das die Anzahl der veränderten Datensätze zu sein.

Man könnte das wie folgt eindampfen (ungetestet):

Code: Alles auswählen

def whatever(filename, beschreibung, ve, inhalt, suchmuster):
    regexp = re.compile(suchmuster, re.U | re.I)
    changes = False
    daten = set()
    with open(filename, 'r') as infile:
        for row in my_reader(infile):
            if row[ve] == 'VE' and row[inhalt] == '1':
                match = regexp.search(row[beschreibung])
                if match:
                    row[inhalt] = (match.group('VALUE') or '1').replace('.', '')
                    changes = True
            
            daten.add(tuple(row))

    if changes:
        write_csv(filename, sorted(daten))
Nobuddy
User
Beiträge: 997
Registriert: Montag 30. Januar 2012, 16:38

Hallo BlackJack,
BlackJack hat geschrieben:@Nobuddy: Überlege Dir mal wie oft Du `re.compile()` mit immer wieder dem selben regulären Ausdruck aufrufst. Da kommt doch bei dem gleichen Ausdruck auch immer wieder ein äquivalentes Objekt als Ergebnis. Also ist es unnötig das ständig aufs neue zu berechnen. Das sollte man *einmal* machen und dann das Ergebnis davon verwenden. Und dann vielleicht auch in `find_digits()` direkt die `search()`-Methode auf dem Objekt aufrufen statt `re.search()` zu verwenden. Das macht ja letztendlich auch nichts anderes als seinerseits dann noch mal die Methode auf dem Objekt aufzurufen. Diese Indirektion kann man sich sparen.
Das war mir so nicht bewußt, danke für den Tip!
BlackJack hat geschrieben:In `find_digits()` verwendest Du `regexp` ohne das man einfach nachvollziehen kann, wo der Wert dafür eigentlich her kommt. Man muss die komplette `get_inhalt()`-Funktion verstehen um zu sehen wo und wie der Name dort an einen oder mehrere Werte gebunden wird. Deshalb würde ich den regulären Ausdruck dort als Argument übergeben.

Die Funktion finde ich aber sowieso etwas übertrieben. Wenn man das „inline” schreibt und statt der Behandlung des `AttributError` das Ergebnis der Suche an einen Namen bindet und damit dann nur weiter macht wenn das Ergebnis nicht `None` ist, kann man das ganze kürzer schreiben und sich auch den unnötigen doppelten Aufruf von `find_digits()` sparen.
Da habe ich noch einiges zu lernen.
BlackJack hat geschrieben:Zu den Gruppennamen: Schau Dir doch bitte mal an was das Wörterbuch enthält. Ein Wörterbuch in eine Liste mit Tupeln aus Schlüssel/Wert-Paare umzuwandeln um dann per verschachtelten Indexzugriff auf einen Wert zuzugreifen ist umständlich und wie gesagt auch *falsch*! Wenn das bei Dir funktioniert, dann ist das reiner Zufall, denn Wörterbücher haben keine Ordnung. Du fragst mit Deinem Code *irgendeinen* zufälligen Wert ab. Das würde nur funktionieren wenn das Wörterbuch nur einen Wert enthalten würde, aber dann wäre die Datenstruktur und der umständliche Zugriff noch unsinniger.
Es ist ja eine TAB-getrennte Textdatei und die Datensätze werden ja zeilenweise abgearbeitet, egal ob die nun sortiert sind oder nicht. Wenn ich nun eine Bedingung voraussetze, so betrifft es ja alles Datensätze gleichermaßen, entweder TRUE oder FALSE.
Oder liege ich da falsch und verstehe Deine Message nicht?
BlackJack hat geschrieben:Der Schleifenkörper ist immer noch viel zu aufgebläht. Wenn etwas am Anfang oder Ende von *jedem* möglichen Zweig passiert, dann muss man das nicht in *jeden* Zweig reinschreiben, sondern *einmal* an passender Stelle. ``daten.append(tuple(r))`` wird in jedem Fall (fast) am Ende der Ausführung eines Schleifendurchlaufs gemacht. Das kann man deshalb auch *einmal* am Ende der Schleife machen. Damit sparst Du zwei ``else``-Zweige. Genau so kann man das erhöhen von `wert` aus dem ``if``/``else`` heraus ziehen. Und von dem Konstrukt bleibt auch nur noch das ``if`` wenn man mal überlegt was denn schlimmes passiert wenn man bei der '1' Tausenderzeichen entfernt.
Einzigstes Problem ist, daß ja nur die Daten in Datei zurückgeschrieben werden, die Wahr sind. Ich benötige ja aber beide TRUE und FALSE, da der Datensatz von FALSE ja nicht wirklich falsch ist, sondern nur nicht in dieser Funktion bearbeitet wird.
BlackJack hat geschrieben:`wert` ist übrigens ein ziemlich schlechter Name, weil nichtssagend. Denn ein Wert ist letztendlich *alles* was man an einen Namen binden kann. Namen sollten beschreiben wofür der daran gebundene Wert steht. In diesem Fall zum Beispiel scheint das die Anzahl der veränderten Datensätze zu sein.
'wert' ist nur ein Zähler für mich, um feststellen zu können, ob Datensätze bearbeitet wurden. Sind keine Datensätze bearbeitet worden, muß ja auch die Datei nicht mit den gleichen Daten überschrieben werden.
BlackJack hat geschrieben:Man könnte das wie folgt eindampfen (ungetestet):

Code: Alles auswählen

def whatever(filename, beschreibung, ve, inhalt, suchmuster):
    regexp = re.compile(suchmuster, re.U | re.I)
    changes = False
    daten = set()
    with open(filename, 'r') as infile:
        for row in my_reader(infile):
            if row[ve] == 'VE' and row[inhalt] == '1':
                match = regexp.search(row[beschreibung])
                if match:
                    row[inhalt] = (match.group('VALUE') or '1').replace('.', '')
                    changes = True
            
            daten.add(tuple(row))

    if changes:
        write_csv(filename, sorted(daten))
Das sieht gut aus, müßte nur noch die Daten, die nicht 'changes = True' und auch nicht 'if row[ve] == 'VE' and row[inhalt] == '1':' sind, wieder in die Datei zusammen zurück schreiben.
Nobuddy
User
Beiträge: 997
Registriert: Montag 30. Januar 2012, 16:38

@BlackJack, Dein Konstrukt funktioniert und meine Befürchtung, daß nicht alle Daten (TRUE + FALSE) in die Datei zurück geschrieben wird, war umsonst. Dies verwirrt mich etwas, da es doch heißt 'if chance:', also 'if True' oder nicht?
Das würde mich interessieren.

Was mir noch nicht klar ist, auch wenn es hier evtl. schon einmal erklärt worden ist: Worin besteht genau der Unterschied zwischen 'daten.add' und 'daten.append'?
BlackJack

@Nobuddy: Bei dem Wörterbuch verstehst Du meine Aussage offensichtlich wirklich nicht. Es geht nicht um die Datensätze als ganzes und ob die sortiert sind, oder nicht, sondern um diesen Ausdruck: ``find_digits(r[beschreibung]).items()[0][1]``. `find_digits()` gibt ein Wörterbuch zurück, und zwar mit so vielen Einträgen wie der reguläre Ausdruck benannte Gruppen hatte. Also bei den bisher gezeigten Ausdrücken sind das zwei. Wenn Du dir eine Liste mit den Schlüssel/Wert-Paaren mit `items()` geben lässt, dann gibt es keinerlei Garantien in welcher Reihenfolge die sind. Du nimmst also einen zufälligen der beiden Werte und arbeitest damit weiter. Nun kann ich mir aber nicht vorstellen, dass es egal ist ob Du den Wert für 'VALUE' oder den Wert für 'UNIT' im weiteren verwendest.

Ich verstehe nicht genau was Du mit es würden „ja nur die Daten in Datei zurückgeschrieben werden, die Wahr sind” meinst, denn Dein Code hängt das Tupel, das aus `r` gebildet wird, in *jedem* möglichen Ablaufpfad an `daten` an. Es gibt keine Kombination von Bedingungen bei der das *nicht* passiert. Falls Du meinst, dass es eine solche gäbe, dann nenne doch mal ein Beispiel für ein `r` das nicht zu `daten` hinzugefügt würde‽

Was der Wert von `wert` bedeuten soll habe ich also richtig erkannt. Es wäre halt bloss schön wenn man das schon am Namen erkennen würde und nicht zwingend nachschauen müsste was daran im Programmverlauf gebunden wird, und wie der Wert am Ende verwendet wird. ;-)

Wieso sollte ``if changes:`` das selbe sein wie ``if True:``? Am Anfang – zweite Zeile der Funktion — wird der Name an `False` gebunden. Und an `True` nur, wenn der Programmverlauf mindestens einmal bis zum innersten ``if`` in der Schleife vordringen kann. Was er nur tut, wenn auch in der Zeile davor tatsächlich der Datensatz verändert wurde.

`daten.append()` funktioniert nicht wenn man `daten` an einen Wert vom Typ `set` gebunden hat. Und `daten.add()` funktioniert nicht bei Listen. :-)
Nobuddy
User
Beiträge: 997
Registriert: Montag 30. Januar 2012, 16:38

Hallo BlackJack,
BlackJack hat geschrieben:@Nobuddy: Bei dem Wörterbuch verstehst Du meine Aussage offensichtlich wirklich nicht. Es geht nicht um die Datensätze als ganzes und ob die sortiert sind, oder nicht, sondern um diesen Ausdruck: ``find_digits(r[beschreibung]).items()[0][1]``. `find_digits()` gibt ein Wörterbuch zurück, und zwar mit so vielen Einträgen wie der reguläre Ausdruck benannte Gruppen hatte. Also bei den bisher gezeigten Ausdrücken sind das zwei. Wenn Du dir eine Liste mit den Schlüssel/Wert-Paaren mit `items()` geben lässt, dann gibt es keinerlei Garantien in welcher Reihenfolge die sind. Du nimmst also einen zufälligen der beiden Werte und arbeitest damit weiter. Nun kann ich mir aber nicht vorstellen, dass es egal ist ob Du den Wert für 'VALUE' oder den Wert für 'UNIT' im weiteren verwendest.
Ich versuche das zu verstehen und glaube, daß der Knoten evtl. geplatzt sein könnte. Verstehe ich das richtig, daß je nach dem wie ich die RegExp aufgebaut habe, in einem Fall 'VALUE' den richtigen Wert hat und bei der nächsten RegExp, 'UNIT' den richtigen Wert hat?
BlackJack hat geschrieben:Ich verstehe nicht genau was Du mit es würden „ja nur die Daten in Datei zurückgeschrieben werden, die Wahr sind” meinst, denn Dein Code hängt das Tupel, das aus `r` gebildet wird, in *jedem* möglichen Ablaufpfad an `daten` an. Es gibt keine Kombination von Bedingungen bei der das *nicht* passiert. Falls Du meinst, dass es eine solche gäbe, dann nenne doch mal ein Beispiel für ein `r` das nicht zu `daten` hinzugefügt würde‽
Da komme ich evtl. später drauf zurück.
BlackJack hat geschrieben:Was der Wert von `wert` bedeuten soll habe ich also richtig erkannt. Es wäre halt bloss schön wenn man das schon am Namen erkennen würde und nicht zwingend nachschauen müsste was daran im Programmverlauf gebunden wird, und wie der Wert am Ende verwendet wird. ;-)
Ok, ich benenne jetzt `wert` in 'zaehler' um.
Diesen Zähler positioniere ich genau an den Stellen, bei denen Daten geändert werden. Ist zwar nicht das Gleiche wie bei Dir 'chance = True', aber hat doch eine gewisse Ähnlichkeit, da ich nur dann die Datei neu beschreibe, wenn auch wirklich Daten geändert wurden. Gleichzeitig kann ich den Zähler auch für eine print-Ausgabe nutzen, z.B. ''print('Es wurden ' + str(zaehler) + ' Änderungen vorgenommen')''.
BlackJack hat geschrieben:Wieso sollte ``if changes:`` das selbe sein wie ``if True:``? Am Anfang – zweite Zeile der Funktion — wird der Name an `False` gebunden. Und an `True` nur, wenn der Programmverlauf mindestens einmal bis zum innersten ``if`` in der Schleife vordringen kann. Was er nur tut, wenn auch in der Zeile davor tatsächlich der Datensatz verändert wurde.

`daten.append()` funktioniert nicht wenn man `daten` an einen Wert vom Typ `set` gebunden hat. Und `daten.add()` funktioniert nicht bei Listen. :-)
Das habe ich jetzt verstanden, Danke! :wink:
Antworten