1

I'm sorry if my title is a bit unclear, I wasn't sure how to express my problem better. I will give a quick code snippet to illustrate what I am trying to do:

for data_file in data_files:
    analyze(data_file)

def analyze(data_file):
    for _ in np.arange(n_steps):
        foo(data_file)
    do some other things

def foo(data_file):
    do some things
    if (value > 1): 
        do some things
        double_return()
    else:
        continue doing other things

What I want the function double_return() to do then, is to return back to the larger loop:

for data_file in data_files:

(Instead of return, which would continue to the next step in for _ in n_steps). However, I am not sure what command to use here and haven't been able to find it.

martineau
  • 119,623
  • 25
  • 170
  • 301
aalvisj
  • 23
  • 4
  • The terminology you're looking for is either "`return`" or "`break`", not "pop". – mtraceur May 21 '22 at 15:06
  • @mtraceur: ... although thinking about it in machine language terms you could do a double `pop` of the program stack. – quamrana May 21 '22 at 15:08
  • You could just check the return value from foo, or define a custom exception. – Kenny Ostrom May 21 '22 at 15:15
  • @quamrana yeah, not even just machine code - at all levels of abstraction, whether machine code, Python bytecode, or Python source - if it has a call stack, you can reasonably apply the word "pop" to it. But that's piercing the most relevant high-level abstraction (return), and using "pop" in the question title makes many Python devs think of stuff like `dict.pop`, and many devs in general think of regular/general stacks. – mtraceur May 21 '22 at 17:20
  • @quamrana P.S. btw machine code doesn't inherently require a call stack (for example, you can implement everything with continuation passing and monads instead of a call stack - the call stack just happens to be a decent design choice which is simple to implement and decently good at expressing many programs). – mtraceur May 21 '22 at 17:41
  • It's just that, of the limited number of CPUs that I've programmed in machine code, everyone has a stack pointer which can be manually popped etc. – quamrana May 21 '22 at 19:17

2 Answers2

1

What you can do is to return a truthy value (assuming all the other routes out of foo() are the default return None) and test for it:

def analyze(data_file):
    for _ in np.arange(n_steps):
        if foo(data_file):
            return
    do some other things

def foo(data_file):
    do some things
    if (value > 1): 
        do some things
        return True
    else:
        continue doing other things

for data_file in data_files:
    analyze(data_file)

It rather obscures the meaning, but it will work in a testable way.

quamrana
  • 37,849
  • 12
  • 53
  • 71
  • Thank you! So if I understand correctly, the None will be interpreted as 'False' in the if statement? – aalvisj May 21 '22 at 14:04
  • 1
    Yes, that's right. There are `Truthy` and `Falsy` values in python as mentioned in the answers to this [question](https://stackoverflow.com/questions/39983695/what-is-truthy-and-falsy-how-is-it-different-from-true-and-false). I added `return True` as the smallest change to your code assuming that all other routes out of `foo()` just return `None` by default. – quamrana May 21 '22 at 14:07
1

foo() could return True, if it completes, or False if you want to “leave early”:

for data_file in data_files:
   analyze(data_file)

def analyze(data_file):
   for _ in np.arange(n_steps):
       if not foo(data_file):
          return
   do some other things

def foo(data_file):
   do some things
   if (value > 1):
       do some things
       return False
   else:
       continue doing other things

   return True

Edit:
To make the meaning clearer, you could define foo_completed=True, and foo_not_completed=False, and use these constants instead of True/False.

martineau
  • 119,623
  • 25
  • 170
  • 301
Stefan
  • 622
  • 1
  • 5
  • 17