Returning from a multiple stacked call at once
Cameron Simpson
cs at cskk.id.au
Sat Dec 12 16:37:42 EST 2020
On 12Dec2020 17:46, ast <ast at invalid> wrote:
>Le 12/12/2020 à 09:18, Cameron Simpson a écrit :
>>On 12Dec2020 07:39, ast <ast at invalid> wrote:
>>>In case a function recursively calls itself many times,
>>>is there a way to return a data immediately without
>>>unstacking all functions ?
>>
>>Not really. Do you have an example where this is inconvenient?
>>There are alternatives, for example passing in a Queue and put()ing
>>the data onto the queue.
[...]
>
>I don't really need it. I was just wondering and guessed it was
>not feasible.
Well, it is feasible. Kinda. Regardless, the stack need to unwind. You
_could_ abuse exceptions to do that in a single go:
class CompletedOperation(Exception):
def __init__(self, value):
self.value = value
... in your function ...
raise CompletedOperation(the_value)
... at the calling end ...
try:
call_the_function(....)
except CompletedOperation as e:
value = e.value
else:
... value not found ...
or obvious variations where that try/except it done by the outermost
function invocation, concealing it from users.
But usually you just return the value from the innermost call and return
that in turn:
def f(....):
for subpart in ... stuff ...:
value = f(subpart)
if value is not None:
return value
return None
which searches some data structure and returns nonNone on finding
something, None if not found.
>Here is a code where it would be useful. This code looks for a
>path in a graph.
>If the found path is long, say 100 nodes, then path_finder calls
>itself recursively 100 times, and has to unstack 100 times to
>provide the found path. It could be returned immediately.
The above code returns efficiently. But there's a cascade of returns.
WRT to the below code, I thought I'd restate what DL Neil has said: you
can often make these things nonrecursive by maintaining a queue or stack
of pending tasks. A recursive function keeps it state in the call stack,
but you needn't do that:
def f(node,...):
pending = [node]
while pending:
node = pending.pop(0)
if node is the one you're looking for:
return node
pending.extend(children of the node here ...)
return None
This keeps a queue of unexamined nodes in pending. You could make that a
stack by replacing the .pop(0) with .pop(). That will be more efficient
(remove the leading element of a list is comparatively expensive) but
changes the search order.
Anyway, this is what DL Neil is referring to: a nonrecursive function
with a data structure to hold the coming work, which a recursive
function would process by calling itself instead of saving the undone
task (chid nodes, here).
Cheers,
Cameron Simpson <cs at cskk.id.au>
More information about the Python-list
mailing list