我可以知道从哪里调用/调用函数吗?

Posted

技术标签:

【中文标题】我可以知道从哪里调用/调用函数吗?【英文标题】:Can I know from where a function has been invoked/called? 【发布时间】:2021-08-07 04:38:11 【问题描述】:

我开始使用 Python 3 进行编程。我想知道是否有任何函数或方法可以让我知道从哪个位置(也许是从哪一行)调用了该函数.

例如,如果我有以下代码...

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

不知何故知道函数:

foo:在第 1 行定义。 它已在第 9 行从main 调用

suma:在第 4 行定义。 已在第 10 行从main 调用。

是否有一些功能可以做到这一点或类似的功能?

可能是这样的:

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

但是有了前面提到的。

【问题讨论】:

也许traceback-module 可以帮助你 您能否详细说明您的实际用例是什么?为什么需要这样做?或者更确切地说,你为什么认为你需要这样做?我这样表述的原因是因为你提到你刚刚开始 - 初学者经常问他们对问题的想象方法的问题,而不是问题本身。如果您分享用例,有人可能会建议另一种方法。 作为旁注,第 15 行中的“else:”子句毫无意义。如果您调用一个不存在的函数,解释器将非常乐意告诉您,并提供有用的错误消息和回溯。永远不要检查您不准备处理的错误情况。 您可以使用调试器知道哪个是调用者。例如,PyCharm else 子句是错误的 - 无论__name__ == "__main__" 是否存在,main 都将存在。这不是 if __name__ == "__main__" 检查的用途。 if __name__ == "__main__" 检查我们是否应该运行文件的脚本功能,而不是我们是否可以这样做。 【参考方案1】:

定义函数的行号。

使用:inspect.getsourcelines(THE_NAME_OF_YOUR_FUNCTION)[1]

函数所在的行。

使用:called.inspect.stack()[1][2]

调用/调用函数。

使用:inspect.stack()[1][3]

(可选)包含它的模块。

使用:THE_NAME_OF_YOUR_FUNCTION.__module__

举个例子……(我添加了一个额外的函数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()

如果我们列出前面的行,代码如下:

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()

你会得到这样的结果:

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.

【讨论】:

【参考方案2】:

inspect 模块是您想要的方式(特别是 .getsourcelines() 方法)。

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)

您会看到结果是一个元组,其中第一个元素是函数的源,第二个元素是定义函数的行。

如果您也需要,还有一个等效的 getsourcefile 方法来获取文件。

【讨论】:

inspect.getsourcelines 没有说明函数从哪里调用 我很高兴就问题的另一半提出建议。当我最初发布此内容时,其他人有一个堆栈解决方案,可以解决问题的那一部分。我只是想解决“foo:它在第 1 行中定义”。部分。

以上是关于我可以知道从哪里调用/调用函数吗?的主要内容,如果未能解决你的问题,请参考以下文章

gdb 使用啥机制来知道在哪里“完成”函数调用?

我们可以从 JavaScript Post 方法调用 aspx.cs 中的非静态函数吗

从其他两个函数调用相同的函数

我可以从 Dart 调用 Kotlin 函数吗

为啥C++里面,析构函数会被调用两次

可以在android中调用javascript函数吗?