return möchte nicht wie ich will

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.
Antworten
oganae
User
Beiträge: 3
Registriert: Freitag 21. Juni 2013, 22:16

Grüße,

ich bin noch relativer Anfänger und schreibe gerade ein kleines Programm was folgendes tun soll.
In einem Ordner sind viele Dateien mit Dateinamen 001, 002, ... 150 (z.B).
Dummerweise fehlen manchmal zwischendrin Datein (die letzte ist aber immer da!) und ich will nun rausfinden welche.
Den ganzen Kram mit Verzeichnissen/Dateinamen lesen ist kein Problem allerdings macht mir meine folgende Funktion zu schaffen:

Code: Alles auswählen

def FehlendeBilder(index_zaehler, end, index_dateizaehler, fehlt_string):
    fehlt = fehlt_string

    if index_zaehler <= end:
        erwartet = index_zaehler + 1
        bekommen = int(bildernummern[index_dateizaehler])

          
        if erwartet != bekommen:
            fehlt = fehlt + str(erwartet)
            FehlendeBilder(index_zaehler+1, end, index_dateizaehler, fehlt)
        else:
            FehlendeBilder(index_zaehler+1, end, index_dateizaehler+1, fehlt)
    else:
        print(fehlt + "THIS LINE WILL BE ALWAYS PRINTED AT THE END")    #prints '78THIS LINE WILL BE ALWAYS PRINTED AT THE END'
        return fehlt # RETURNS 'none'

Aufrufen tue ich das woanders mittels

Code: Alles auswählen

print(FehlendeBilder(0, int(bildernummern[-1])-1, 0,""))
So was macht das Teil (meiner Meinung nach):
1) Wird aufgerufen mit
- index_zaehler = 0 als dem Startwert zum Hochzählen,
- int(bildernummern[-1])-1 # das soll aus der Liste mit den Dateinamen den letzten Wert (=der Höchste, da wir davon ausgehen, dass die letzte Datei immer vorhanden ist) nehmen und davon 1 abziehen damit man nachher vergleichen kann (die Liste fängt bei 0 an, aber die Dateien bei 1, also muss man halt eins weniger durchgehen).
- index_dateizaehler = 0 als dem Zähler, welche Datei nun kommen müsste,
- fehlt_string = "" das ist der string den ich mitschleppen will in den dann immer der Name der fehlenden Datei eingetragen wird.

----
So der Witz an dem Ganzen, und was ich überhaupt nicht verstehe, ist das, was in den letzten beiden Zeilen passiert

Dort steht:

Code: Alles auswählen

print(fehlt + "THIS LINE WILL BE ALWAYS PRINTED AT THE END")    #prints '78THIS LINE WILL BE ALWAYS PRINTED AT THE END'
return fehlt # RETURNS 'none'
Also das print liefert ohne Probleme den Wert für 'fehlt' aus (78 in meinem Fall, was auch richtig ist), allerdings gibt das return direkt darunter nur ein None aus.

Warum?

Danke
BlackJack

@oganae: Es ist nicht *das* ``return`` sondern das implizite ``return None`` am Ende der Funktion. Wenn eine Funktion bis ans Ende durch läuft, ohne dass ein ``return`` ausgeführt wird, dann gibt die Funktion `None` zurück.

Wenn der ``if``-Zweig ausgeführt wird, dann steht da nirgends ein ``return``, also gibt der Funktionsaufruf `None` zurück.

Das ist aber alles nur ein theoretisches Problem, den praktisch verwendet man in Python keine Rekursion für so etwas, weil das ineffizient ist und nicht skaliert. Wenn man erst einmal anfängt so zu programmieren, wird man früher oder später das Rekursionslimit erreichen und das Programm bricht mit einer Ausnahme ab. Wenn man einfach nur Code wiederholt ausführen möchte, dann verwendet man ``for`` oder ``while``.

Ein weiteres Problem ist `bildernummern` was in der Funktion verwendet, aber nicht als Argument übergeben wird. Das ist unsauber.

Vorausgesetzt man hat eine Sequenz mit aufsteigenden Bildernummern:

Code: Alles auswählen

def fehlende_bilder(bildernummern):
    result = list()
    offset = 0
    for i, nummer in enumerate(bildernummern):
        expected = offset + i
        missing_count = nummer - expected
        if missing_count < 0:
            raise ValueError('Bildernummern nicht aufsteigend.')
        result.extend(xrange(expected, expected + missing_count))
        offset += missing_count
    return result
oganae
User
Beiträge: 3
Registriert: Freitag 21. Juni 2013, 22:16

So habe es nun selbst gelöst (bevor ich deinen Edit sah):

Code: Alles auswählen

        zaehler = 0
        offset = 0
        fehlend = []
        while zaehler < int(bildernummern[-1]):
            try:
                if zaehler+1 != int(bildernummern[zaehler-offset]):
                    fehlend.append(zaehler+1) 
                    offset+=1
            except:
                fehlend.append(zaehler+1) 
                offset+=1
            zaehler+=1
            
        print(fehlend)
Den ganzen try kram brauchte ich, da sonst der listindex zu groß wird.
Gibt es nicht sowas wie ein if list[n]: - also solange es keinen Fehler gibt führe es aus? Try/Except sieht unschön aus :/
Benutzeravatar
snafu
User
Beiträge: 6740
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

oganae hat geschrieben:Den ganzen try kram brauchte ich, da sonst der listindex zu groß wird.
Gibt es nicht sowas wie ein if list[n]: - also solange es keinen Fehler gibt führe es aus? Try/Except sieht unschön aus :/
Es gibt `for`-Schleifen und zum Durchnummerieren `enumerate()` bzw `xrange()` - siehe BlackJacks Beitrag.
Sirius3
User
Beiträge: 17747
Registriert: Sonntag 21. Oktober 2012, 17:20

@oganae: noch etwas zu Deiner Lösung: Bei Deinem »try-expect« erwartest Du einen »IndexError« also solltest Du auch nur diesen abfangen.

Die Streberlösung:

Code: Alles auswählen

def fehlende_bilder(bildernummern):
    bildernummern = set(bildernummern)
    return sorted(set(range(max(bildernummern))) - bildernummern)
Benutzeravatar
snafu
User
Beiträge: 6740
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

@Sirius3: Das wird aber nicht so gut für Bildernummern mit dem Schema `001`, `002`, `003`, etc funktionieren. Und der Threadersteller schrieb eingangs, dass er ein solches Format (und zudem also auch Strings) vorliegen hat. BlackJack geht in seinem Code ja davon aus, dass eine vorsortierte Sequenz vorliegt und arbeitet damit unabhängig vom tatsächlichen Format - das ist dementsprechend schön flexibel. Lediglich bei der Rückgabe hat man es dann noch mit den nackten Zahlen anstatt mit formatierten Strings zu tun.

EDIT: Evtl will man die Sortierung sogar innerhalb der Funktion erledigen lassen, sodass ein Anwender bloß die Ausgabe von `os.listdir()` bzw `glob.glob()` übergeben muss, ohne sich allzu sehr auf Vorgaben durch die interne Vorgehensweise der Funktion einlassen zu müssen. Aber das sind natürlich nur Details, die man so oder so handhaben kann.

EDIT2: Wobei direkte Ergebnisse von Ausgaben mit Dateinamen ja eh nicht funktionieren würden. Offenbar liegen die Daten schon einigermaßen geeignet aufbereitet vor. In dem Fall könnte man vom Anwender wohl tatsächlich auch ein `sorted(map(int, bildernummern))` erwarten.
Antworten