Home > Net >  Check if a function has been called from a loop
Check if a function has been called from a loop

Time:12-29

Is it possible to check dynamically whether a function has been called from within a loop?

Example:

def some_function():
    if called_from_loop:
        print("Hey, I'm called from a loop!")

for i in range(0, 1):
    some_function()

some_function()

Expected output:

> Hey, I'm called from a loop!

CodePudding user response:

Not sure if this is going to be 100% reliable. It's also rather cumbersome and would have to be written inside the function of interest rather than in its own discrete function for fairly obvious reasons.

We can get the source code for the currently executing .py file

We can also get a stack trace.

Therefore, we can determine the line number in the code from where our function has been called. Thus we can navigate the source code (backwards) taking care to note indentation and see where the indentation decreases and if the line where that occurs starts with either 'for' or 'while' then we were called from within a loop.

So here's the fun:

import traceback
import inspect
import sys

def getws(s):
    return len(s) - len(s.lstrip())

def func():
    source = inspect.getsource(sys.modules[__name__]).splitlines()
    stack = traceback.extract_stack()
    lineno = stack[-2].lineno-1
    isLooped = False
    if (ws := getws(source[lineno])) > 0:
        for i in range(lineno-1, -1, -1):
            if (_ws := getws(line := source[i])) < ws:
                if (tokens := line.split()) and tokens[0] in {'for', 'while'}:
                    isLooped = True
                    break
                if (ws := _ws) == 0:
                    break
    print('Called from loop' if isLooped else 'Not from loop')

def looper():
    for _ in range(1):
        # banana
        func()

def looper2(): # this code is nonsense
    i = 5
    while i > 0:
        if i < 10:
            func()
            break

looper()
looper2()
func()
while True:
    func()
    break
if __name__ == '__main__':
    func()

Output:

Called from loop
Called from loop
Not from loop
Called from loop
Not from loop

CodePudding user response:

You can always try something like this:

def some_function(caller=0):
    if caller == 1:
        print("Hey, I'm called from a loop!")
        
    if caller == 2:
        print("Wow, I'm called from a list comprehension")
        
    print('Whatever\n')

for i in range(0, 1):
    some_function(1)
    
a = [some_function(2) for i in range(3)]

some_function()
Hey, I'm called from a loop!
Whatever

Wow, I'm called from a list comprehension
Whatever

Wow, I'm called from a list comprehension
Whatever

Wow, I'm called from a list comprehension
Whatever

Whatever
  • Related