Aktuelle Rekursionstiefe feststellen

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
chris_98
User
Beiträge: 2
Registriert: Samstag 23. September 2017, 11:29

Guten Morgen liebe Community,

folgendes Problem: Ich habe eine Funktion, die sich je nach den übergebenen/bearbeiteten Parametern möglicherweise rekursiv aufruft.
Aber ich möchte, dass, unabhängig vom Zustand der Parameter, dieses rekursive Aufrufen nicht öfter als fünfmal passiert. Daher, sollte die Rekursionstiefe fünf erreichen/überschreiten, soll die Funktion einfach False zurückgeben - oder so.

Bisher mache ich das einfach mit einem Funktionsattribut, das halt mitzählt. Dafür muss ich aber zuerst testen ob dieses Attribut existiert etc... Da wird der Code schnell mal für meine Begriffe chaotisch.
Gibt es da eine einfachere Lösung? Also einfach den Test "Rekursionstiefe > 5" - oder so?

Danke für die Hilfe!
Liebe Grüße, Christoph
__deets__
User
Beiträge: 14529
Registriert: Mittwoch 14. Oktober 2015, 14:29

Ich Verstehe den Begriff Funktionsattribut nicht. Meinst du eine Parameter? Das ist die einfachste und sauberste Lösung. Und eine automatismus gibt es nicht, das muss man schon so programmieren.
Sirius3
User
Beiträge: 17741
Registriert: Sonntag 21. Oktober 2012, 17:20

@chris_98: Zeig doch einfach Deine Funktion und beschreib, was Dir daran nicht gefällt. Vielleicht findet sich ja eine bessere Lösung.
nezzcarth
User
Beiträge: 1633
Registriert: Samstag 16. April 2011, 12:47

__deets__ hat geschrieben:Ich Verstehe den Begriff Funktionsattribut nicht.
Gemeint ist vielleicht etwas in der Richtung:

Code: Alles auswählen

In [1]: def test():
   ...:     calls = getattr(test, "calls", 0)
   ...:     print('Calls:', calls)
   ...:     if calls < 5:
   ...:         setattr(test, "calls", calls + 1)
   ...:         test()
   ...:     else:
   ...:         print('Exceeded.')
   ...:         return

In [2]: test()
Calls: 0
Calls: 1
Calls: 2
Calls: 3
Calls: 4
Calls: 5
Exceeded.

In [3]: test()
Calls: 5
Exceeded.

Von der Verwendung würde ich hier aber abraten.
Benutzeravatar
snafu
User
Beiträge: 6738
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Wobei ich unter Rekursionstiefe nicht die Anzahl der Funktionsaufrufe verstehe. Da bringst du wohl was durcheinander.
Melewo
User
Beiträge: 320
Registriert: Mittwoch 3. Mai 2017, 16:30

@snafu: Das habe ich bisher nicht anders verstanden. Nach meinem bisherigen Verständnis bedeutet Rekursionstiefe, wie oft "def test()" sich rekursiv in der Zeile 6 mit "test()" selbst aufruft. Beruht diese Annahme auf ein Missverständnis?
nezzcarth
User
Beiträge: 1633
Registriert: Samstag 16. April 2011, 12:47

snafu hat geschrieben:Wobei ich unter Rekursionstiefe nicht die Anzahl der Funktionsaufrufe verstehe. Da bringst du wohl was durcheinander.
Wie verstehst du denn Rekursionstiefe? Mein Beispiel zählt die Anzahl der inneinander verschachtelten Aufrufe. Ist das nicht die Rekursionstiefe?
Lasse ich mein Beispiel leicht abgewandelt als eigenständiges Skript laufen, komme ich jedenfalls an das Rekursionslimit (abzüglich des Frames, das inital schon auf dem Stack liegt).

Code: Alles auswählen

#!/usr/bin/env python3
import sys
import inspect

def test():
    calls = getattr(test, "calls", 0)
    setattr(test, "calls", calls + 1)
    try:
        test()
    except RecursionError:
        print('calls ', calls)
        print('Stack', len(inspect.stack()))
    return

if __name__ == '__main__':
    print('Stack', len(inspect.stack()))
    print('Recursion Depth:', sys.getrecursionlimit())
    test()

Code: Alles auswählen

% ./recursion_test.py
Stack 1
Recursion Depth: 1000
calls  998
Stack 1000
Zuletzt geändert von nezzcarth am Sonntag 24. September 2017, 14:00, insgesamt 2-mal geändert.
__deets__
User
Beiträge: 14529
Registriert: Mittwoch 14. Oktober 2015, 14:29

Na kommt drauf an. Für baumartige rekursionen ist dein erster Ansatz zu simpel. Prinzipiell würde ich sowas auch per Dekoration umsetzten. Dann kannst du auch wieder ‚poppen‘ wenn du austrittst.

Und der zweite impliziert das du immer nur die Funktion selbst aufrufst. Das ist oft, aber nicht immer so.

So oder so würde ich das nicht so machen. Ist globaler Zustand. Aber für eine bessere Beurteilung fehlen Informationen.
Benutzeravatar
kbr
User
Beiträge: 1487
Registriert: Mittwoch 15. Oktober 2008, 09:27

Schlepp die Rekursionstiefe doch einfach als Parameter mit:

Code: Alles auswählen

def recursive_function(arg='LA ', max_depth=5, current_depth=1):
    if current_depth >= max_depth:
        return arg
    return arg + recursive_function(arg, max_depth, current_depth+1)
Hilft bei baumartigen Strukturen sicherlich nicht. Ich halte es allerdings auch für fraglich, ob bei solchen Strukturen die "Rekursionstiefe" alleine eine sinnvolle Abbruchbedingung darstellt.
Sirius3
User
Beiträge: 17741
Registriert: Sonntag 21. Oktober 2012, 17:20

@nezzcarth: Du verwendest bei Deinem Beispiel eine globale Variable und kannst insgesamt `test` nur 5 mal aufrufen, wie Du in Deinem Beispiel schön zeigst, das versteht man normalerweise nicht unter Rekursion. kbr's Methode ist der empfohlene Weg.
Benutzeravatar
snafu
User
Beiträge: 6738
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Rekursionstiefe meint über wieviele Ebenen "nach unten" die Funktionsaufrufe gehen. Dabei kann es sich aber durchaus um mehr als nur eine Funktion handeln. Zudem ist es nicht sinnvoll, die Funktion selbst einfach mit der Anzahl ihrer Aufrufe zu bestücken. Was passiert wohl, wenn sich die Funktion z.B. nur dreimal aufgerufen hat und später nochmals verwendet werden soll...?
chris_98
User
Beiträge: 2
Registriert: Samstag 23. September 2017, 11:29

kbr hat geschrieben:Schlepp die Rekursionstiefe doch einfach als Parameter mit:

Code: Alles auswählen

def recursive_function(arg='LA ', max_depth=5, current_depth=1):
    if current_depth >= max_depth:
        return arg
    return arg + recursive_function(arg, max_depth, current_depth+1)
Hilft bei baumartigen Strukturen sicherlich nicht. Ich halte es allerdings auch für fraglich, ob bei solchen Strukturen die "Rekursionstiefe" alleine eine sinnvolle Abbruchbedingung darstellt.
Aah! Das schaut doch schon weitaus aufgeräumter aus :)

Ich glaub, damit kann ich mich anfreunden...
Meine Methode war ein Attribut im Sinne von test.current_depth. Das geht zwar, aber dann muss man es irgendwann mal wieder zurücksetzen und/oder so - und da wirds dann chaotisch...

Nur zur Klarstellung - die Rekursionstiefe ist nur ein Abbruchkriterium, das ich im besten Fall garnicht brauche...
Antworten