【问题标题】: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__" 检查我们是否应该运行文件的脚本功能,而不是我们是否可以这样做。

标签: python python-3.x


【解决方案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 行中定义”。部分。
    猜你喜欢
    • 2012-07-02
    • 2018-07-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-08-10
    • 2018-03-02
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多