【问题标题】:Determine function name from within an aliased function从别名函数中确定函数名
【发布时间】:2018-08-19 03:11:51
【问题描述】:

如何确定一个函数是使用函数名还是该函数的别名调用的?

我可以通过以下方式检查函数以从函数体内获取其名称:

import inspect

def foo():
   print(inspect.stack()[0][3])

foo() # prints 'foo'

来源:Determine function name from within that function (without using traceback)

但是,如果我为函数设置别名并尝试相同的操作,我会得到原始函数名称(不是别名)

bar = foo
bar() # prints 'foo'

我希望能够做到以下几点:

def foo():
    print(... some code goes here ...)

bar = foo

foo() # prints 'foo'
bar() # prints 'bar'

【问题讨论】:

  • 无法保证用于调用您的函数的引用是从任何名称获得的。可能是l = [foo]; l[0]()sorted(some_list, key=l[0])
  • 这很好,我想在这种情况下l[0]() 应该打印l[0]

标签: python python-3.x introspection


【解决方案1】:

我有一个(有点老套)的解决方案,它依赖于正则表达式从字符串中解析出函数名。可能有一个更清洁的解决方案,但至少使用 inspect only 这是我能找到的最好的。

import inspect
import re


function_from_call = re.compile("\w+(?=\(\))")


def foo():
    _, call_frame, *_ = inspect.stack()
    _, _, _, _, call, *_ = call_frame
    print(re.search(function_from_call, str(call)).group())

bar = foo
bar()  # prints bar
foo()  # prints foo

简短说明:首先,我正在抓取导致调用此函数的调用的检查帧。然后,我从这个框架中提取实际的调用字符串,并将一个正则表达式应用于这个调用字符串,它只给我们函数名称。

注意:在解释器 shell 中,inspect 的行为不同,我上面的代码会产生错误,因为我的正则表达式无法匹配实际的函数名称。 @user2357112 在对此问题的评论中指出了一个额外的警告:调用与名称直接相关并不明显,如

l = [foo]; l[0]()

当从脚本运行时,我的解决方案将正确处理简单的重命名案例(如本问题中给出的那样),但我不提倡使用它,因为上述极端案例会导致令人困惑的错误。

【讨论】:

  • 我真的很想看到这个工作!但是你的正则表达式对我来说什么都不匹配。
  • 这很奇怪。您是否完全按照此处提供的方式使用了我的代码?我得到了评论的打印输出。我正在使用 Python 3.5.2。万一它以某种方式发挥作用.. 编辑并注意:我不确定我的正则表达式是否可以按原样处理任意命名的函数(这就是我在上面将其称为“hack”的原因)。
  • 我使用的是 Python 3.6.2,inspect 模块可能略有不同
  • 而当我使用inspect.stack()时,不出所料,函数名仍然是foo。
  • 我在 pyenv 中安装了 Python 3.6.2,但用它运行我的脚本仍然给我描述的输出......神秘。但请注意@JacobIRR 的答案(绕过正则表达式)使用与我相同的检查访问权限。
【解决方案2】:

根据我对您问题范围的有限了解,这是可行的:

import inspect

def foo():
  print(inspect.stack()[1][4][0].strip())

foo()
bar = foo
bar()

结果:

foo()
bar()

【讨论】:

  • 这对我来说会引发“NoneType not subscriptable”错误。我可以改用inspect.stack()[0][3] 让它工作,但它仍然返回'foo'。知道如何实际完成这项工作吗?
  • 它在解释器中不起作用,但作为脚本起作用。
  • 谢谢,这对我有用(无论是在解释器中还是在 python3.6 的脚本中),并且还具有在括号中给出参数的额外好处。
  • @OlivierMelançon,哎呀.. 似乎任何解决方案都将是 hacky。我能想到的唯一另一件事是遍历堆栈的所有部分并打印函数名称,如果它不是原始名称,但仍然是 hack
  • @JacobIRR 好吧,我真的很惊讶你可以让它像 hacky 一样工作,干得好!
猜你喜欢
  • 1970-01-01
  • 2018-10-28
  • 1970-01-01
  • 2011-07-01
  • 2010-09-13
  • 2011-01-11
相关资源
最近更新 更多