从检查堆栈中获取完全限定方法名

6
我有困难完成以下功能:
def fullyQualifiedMethodNameInStack(depth=1):
    """
    The function should return <file>_<class>_<method> for the method in the 
    stack at specified depth.
    """
    fileName=inspect.stack()[depth][1]
    methodName=inspect.stack()[depth][3]
    class= """ please help!!! """
    baseName=os.path.splitext( os.path.basename( fileName ) )[0]
    return '{0}_{1}_{2}'.format( baseName, className, methodName )

正如你所看到的,我想要执行方法的类名。inspect返回的堆栈只有方法名,我不知道如何找到该方法所属的类。


  1. 你只能看到函数,而非方法。
  2. 你只能就实例的类型做出有根据的猜测,那并不等同于该方法最初定义所在的类。这样足够吗?
- Martijn Pieters
我希望能够找到一个不需要猜测的方法来确定函数定义在哪个类中。我可以做出最有根据的猜测是什么? - andreas buykx
@MartijnPieters 我对第二点很感兴趣。inspect.stack()似乎只能一致地返回函数名称,而不是函数对象。 - millimoose
@millimoose:确切地说,堆栈只记录当前正在执行的函数名称。这也不一定是访问它的名称。 - Martijn Pieters
@MartijnPieters 这有点令人惊讶,我本来以为实际的函数对象会在某个地方出现。尽管即使如此,这也可能不完美,特别是考虑到我认为Python解释器最终会首先“展开”绑定方法对象。 - millimoose
@millimoose:增加了有关堆栈对象、函数和方法以及实例性质的更多阐述。 - Martijn Pieters
1个回答

3
您总是在查看一个函数上下文;方法上下文在函数执行时已经消失。严格来说,当作为实例属性(instance.method_name)访问时,函数充当描述符,返回一个方法对象。然后,当调用该方法对象时,它又会以实例作为第一个参数调用原始函数。因为所有这些都发生在 C 代码中,所以 Python 栈上不再保留原始方法对象的任何痕迹。
栈只需要跟踪命名空间和本地命名空间要执行的代码。对于这些函数,不再需要原始函数对象,只有附加的代码对象仍然保留了原始函数定义的名称,以便进行回溯。
如果您知道函数是一个方法,您可以搜索self本地名称。如果存在,则type(self)实例的类,这不一定是定义方法的类。
然后,您需要搜索类及其基类(循环遍历.__mro__属性),以尝试找到定义该方法的类。

你需要考虑一些其他的问题:

  • 给一个方法的第一个参数命名为self只是一种约定。如果有人选择了不同的名称,你将无法在不解析Python源代码的情况下找到它,或者通过上溯一步并尝试从那一行推断出函数的调用方式,然后检索方法及其.im_self属性。

  • 你只能得到函数最初定义时的名称。这不一定是它被调用时的名称。函数是一等对象,可以以不同的名称添加到类中。

  • 尽管一个函数被传递给了self并作为类定义的一部分被定义,但它也可能是通过手动传递self值而不是作为方法(作为函数充当描述符的结果)传递调用者的self引用来调用的。

在Python 3.3及以上版本中,情况稍微好一些;函数对象有一个新的__qualname__属性,其中包括类名。问题是你仍然需要从父堆栈帧中定位函数对象。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接