Seite 1 von 1
Aktuelle Rekursionstiefe feststellen
Verfasst: Sonntag 24. September 2017, 10:01
von chris_98
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
Re: Aktuelle Rekursionstiefe feststellen
Verfasst: Sonntag 24. September 2017, 10:06
von __deets__
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.
Re: Aktuelle Rekursionstiefe feststellen
Verfasst: Sonntag 24. September 2017, 10:13
von Sirius3
@chris_98: Zeig doch einfach Deine Funktion und beschreib, was Dir daran nicht gefällt. Vielleicht findet sich ja eine bessere Lösung.
Re: Aktuelle Rekursionstiefe feststellen
Verfasst: Sonntag 24. September 2017, 11:45
von nezzcarth
__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.
Re: Aktuelle Rekursionstiefe feststellen
Verfasst: Sonntag 24. September 2017, 13:03
von snafu
Wobei ich unter Rekursionstiefe nicht die Anzahl der Funktionsaufrufe verstehe. Da bringst du wohl was durcheinander.
Re: Aktuelle Rekursionstiefe feststellen
Verfasst: Sonntag 24. September 2017, 13:45
von Melewo
@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?
Re: Aktuelle Rekursionstiefe feststellen
Verfasst: Sonntag 24. September 2017, 13:52
von nezzcarth
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
Re: Aktuelle Rekursionstiefe feststellen
Verfasst: Sonntag 24. September 2017, 13:57
von __deets__
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.
Re: Aktuelle Rekursionstiefe feststellen
Verfasst: Sonntag 24. September 2017, 14:40
von kbr
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.
Re: Aktuelle Rekursionstiefe feststellen
Verfasst: Sonntag 24. September 2017, 18:40
von Sirius3
@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.
Re: Aktuelle Rekursionstiefe feststellen
Verfasst: Sonntag 24. September 2017, 18:54
von snafu
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...?
Re: Aktuelle Rekursionstiefe feststellen
Verfasst: Montag 25. September 2017, 10:15
von chris_98
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...