2

I'm starting to program in Python 3. And I was wondering if there is any function or method that allows me to know from which place (perhaps, from which line) the function was invoked.

For example, if I have the following code...

1  def foo():
2      print("Hi!")
3
4  def suma(a, b):
5      return a+b
6
7
8  def main():
9      foo()
10     suma(3,6)
11
12 
13 if __name__ == "__main__":
14     main()
15 else:
16     print("Function main() not exist")
17

Somehow know that the function:

foo: It is defined in line 1. It has been called from main on line 9

suma: It is defined in line 4. It has been called from main on line 10.

Is there some function that does this or maybe something similar?

Maybe something like:

foo.__ code __. co_nlocals
suma.__ code __. co_nlocals

But with the aforementioned.

mkrieger1
  • 19,194
  • 5
  • 54
  • 65
  • Maybe the [traceback](https://docs.python.org/3/library/traceback.html#traceback.print_stack)-module can help you – Sven Eberth May 17 '21 at 22:33
  • 4
    Could you elaborate on what your actual use-case is? Why do you need to do this? Or rather, why do you think you need to do this? The reason I'm phrasing it this way is because you mentioned that you're just starting out - beginners often ask questions about their imagined approach to a problem, rather than the problem itself. It's possible that, if you share the use-case, someone may be able to suggest an alternative approach. – Paul M. May 17 '21 at 22:33
  • As a side comment, the "else:" clause in line 15 is pointless. If you call a function that doesn't exist, the interpreter will be perfectly happy to tell you that, with a helpful error message and a traceback. Never check for an error condition you aren't prepared to handle. – Tim Roberts May 17 '21 at 22:35
  • You can use debugger to know which is the caller. For example, with [PyCharm](https://www.jetbrains.com/help/pycharm/debugging-your-first-python-application.html#where-is-the-problem) – Tuan Chau May 17 '21 at 22:38
  • That `else` clause is wrong - `main` will exist whether or not `__name__ == "__main__"`. That's not what `if __name__ == "__main__"` checks are for. `if __name__ == "__main__"` checks whether we *should* run the file's script functionality, not whether we *can* do that. – user2357112 May 17 '21 at 22:51
  • Possible Duplicate? [How to get the calling function, not just its name?](https://stackoverflow.com/questions/39078467/python-how-to-get-the-calling-function-not-just-its-name) – 12944qwerty May 17 '21 at 22:53
  • I don't quite understand where and how you would use that. I don't wanna question the legitimacy of the question, but how it is phrased. If you're not using that extensively throughout your program you could just pass a parameter indicating the caller – muzzletov May 18 '21 at 00:29
  • https://stackoverflow.com/questions/961048/get-class-that-defined-method – marienbad May 18 '21 at 22:15

2 Answers2

2
  • Line number in which the function is defined.

    Use: inspect.getsourcelines(THE_NAME_OF_YOUR_FUNCTION)[1]

  • Line from which the function has been.

    Use: called.inspect.stack()[1][2]

  • Invoking/calling function.

    Use: inspect.stack()[1][3]

  • (optional) Module in which it is contained.

    Use: THE_NAME_OF_YOUR_FUNCTION.__module__

As an example ... (I have added an additional function X)

import inspect

def foo(msg):
    print(msg)
    ###▼ YOUR INSPECTION CODE ▼###
    print("\t«{}»\tLine number in which the function is defined.".
           format(inspect.getsourcelines(foo)[1]))
    print("\t«{}»\tLine from which the function has been called.".
           format(inspect.stack()[1][2]))
    print("\t«{}»\tInvoking/calling function.".format(inspect.stack()[1][3]))
    print("\t«{}»\tModule in which it is contained.\n".format(foo.__module__))

def suma(a, b):
    foo("Call from [suma()], on the line [14]")
    return a+b

def difference(a, b):
    foo("Call from [difference()], on the line [18]")
    return a-b

def main():
    foo("Call from [main()], on the line [22]")
    suma(3,6)
    foo("Call from [main()], on the line [24]")
    difference(5,2)

if __name__ == "__main__":
    main()

If we list the previous lines, the code would be as follows:

01    import inspect
02    
03    def foo(msg):
04        print(msg)
05        ###▼ YOUR INSPECTION CODE ▼###
06        print("\t«{}»\tLine number in which the function is defined.".
07               format(inspect.getsourcelines(foo)[1]))
08        print("\t«{}»\tLine from which the function has been called.".
09               format(inspect.stack()[1][2]))
10        print("\t«{}»\tInvoking/calling function.".format(inspect.stack()[1][3]))
11        print("\t«{}»\tModule in which it is contained.\n".format(foo.__module__))
12    
13    def suma(a, b):
14        foo("Call from [suma()], on the line [14]")
15        return a+b
16    
17    def difference(a, b):
18        foo("Call from [difference()], on the line [18]")
19        return a-b
20    
21    def main():
22        foo("Call from [main()], on the line [22]")
23        suma(3,6)
24        foo("Call from [main()], on the line [24]")
25        difference(5,2)
26    
27    if __name__ == "__main__":
28        main()

You will get as a result:

Call from [main()], on the line [22]
    «3»     Line number in which the function is defined.
    «22»    Line from which the function has been called.
    «main»  Invoking/calling function.
    «__main__»  Module in which it is contained.

Call from [suma()], on the line [14]
    «3»     Line number in which the function is defined.
    «14»    Line from which the function has been called.
    «suma»  Invoking/calling function.
    «__main__»  Module in which it is contained.

Call from [main()], on the line [24]
    «3»     Line number in which the function is defined.
    «24»    Line from which the function has been called.
    «main»  Invoking/calling function.
    «__main__»  Module in which it is contained.

Call from [difference()], on the line [18]
    «3»     Line number in which the function is defined.
    «18»    Line from which the function has been called.
    «difference»    Invoking/calling function.
    «__main__»  Module in which it is contained.
Federica F.
  • 225
  • 1
  • 5
-1

the inspect module is how you'd want to go about this (and specifically the .getsourcelines() method).

def foo():
    print("Hi!")
    
def suma(a, b):
    return a+b

import inspect
print(inspect.getsourcelines(foo))
print(inspect.getsourcelines(suma))

(['def foo():\n', ' print("Hi!")\n'], 1)
(['def suma(a, b):\n', ' return a+b\n'], 4)

You'll see that the result is a tupple where the first element is the source of the function, and the second element is the line where the function was defined.

There is an equivalent getsourcefile method to get the file if you need that as well.

  • `inspect.getsourcelines` doesn't say anything about where a function was *called from*. – user2357112 May 17 '21 at 22:51
  • I'm happy to take a suggestion on the other half of the problem. When I originally posted this someone else had a solution with stack that got at that part of the problem. I was just trying to solve the "foo: It is defined in line 1." part. – Tyler Rosacker May 17 '21 at 23:05