代码之家  ›  专栏  ›  技术社区  ›  zs2020

如何在被调用的方法中获取调用方的方法名?

  •  133
  • zs2020  · 技术社区  · 16 年前

    python:如何在被调用的方法中获取调用方的方法名?

    假设我有两种方法:

    def method1(self):
        ...
        a = A.method2()
    
    def method2(self):
        ...
    

    如果我不想对method1做任何更改,如何在method2中获取调用方的名称(在本例中,名称是method1)?

    7 回复  |  直到 7 年前
        1
  •  178
  •   Yuval Pruss    7 年前

    inspect.getframeinfo 以及其他相关职能 inspect 可以帮助:

    >>> import inspect
    >>> def f1(): f2()
    ... 
    >>> def f2():
    ...   curframe = inspect.currentframe()
    ...   calframe = inspect.getouterframes(curframe, 2)
    ...   print('caller name:', calframe[1][3])
    ... 
    >>> f1()
    caller name: f1
    

    这种自省的目的是帮助调试和开发;不建议将其用于生产功能。

        2
  •  74
  •   Todd Owen    14 年前

    较短版本:

    import inspect
    
    def f1(): f2()
    
    def f2():
        print 'caller name:', inspect.stack()[1][3]
    
    f1()
    

    (感谢@alex, Stefaan Lippen )

        3
  •  37
  •   Augiwan Sarju Palukashi    11 年前

    这似乎很管用:

    import sys
    print sys._getframe().f_back.f_code.co_name
    
        4
  •  24
  •   anatoly techtonik Tony    9 年前

    我提出了一个稍微长一点的版本,试图构建一个完整的方法名,包括模块和类。

    https://gist.github.com/2151727 (Rev 9ccCBF)

    # Public Domain, i.e. feel free to copy/paste
    # Considered a hack in Python 2
    
    import inspect
    
    def caller_name(skip=2):
        """Get a name of a caller in the format module.class.method
    
           `skip` specifies how many levels of stack to skip while getting caller
           name. skip=1 means "who calls me", skip=2 "who calls my caller" etc.
    
           An empty string is returned if skipped levels exceed stack height
        """
        stack = inspect.stack()
        start = 0 + skip
        if len(stack) < start + 1:
          return ''
        parentframe = stack[start][0]    
    
        name = []
        module = inspect.getmodule(parentframe)
        # `modname` can be None when frame is executed directly in console
        # TODO(techtonik): consider using __main__
        if module:
            name.append(module.__name__)
        # detect classname
        if 'self' in parentframe.f_locals:
            # I don't know any way to detect call from the object method
            # XXX: there seems to be no way to detect static method call - it will
            #      be just a function call
            name.append(parentframe.f_locals['self'].__class__.__name__)
        codename = parentframe.f_code.co_name
        if codename != '<module>':  # top level usually
            name.append( codename ) # function or a method
    
        ## Avoid circular refs and frame leaks
        #  https://docs.python.org/2.7/library/inspect.html#the-interpreter-stack
        del parentframe, stack
    
        return ".".join(name)
    
        5
  •  9
  •   Xie Yanbo    9 年前

    上面的东西有点混合了。但这是我的破绽。

    def print_caller_name(stack_size=3):
        def wrapper(fn):
            def inner(*args, **kwargs):
                import inspect
                stack = inspect.stack()
    
                modules = [(index, inspect.getmodule(stack[index][0]))
                           for index in reversed(range(1, stack_size))]
                module_name_lengths = [len(module.__name__)
                                       for _, module in modules]
    
                s = '{index:>5} : {module:^%i} : {name}' % (max(module_name_lengths) + 4)
                callers = ['',
                           s.format(index='level', module='module', name='name'),
                           '-' * 50]
    
                for index, module in modules:
                    callers.append(s.format(index=index,
                                            module=module.__name__,
                                            name=stack[index][3]))
    
                callers.append(s.format(index=0,
                                        module=fn.__module__,
                                        name=fn.__name__))
                callers.append('')
                print('\n'.join(callers))
    
                fn(*args, **kwargs)
            return inner
        return wrapper
    

    用途:

    @print_caller_name(4)
    def foo():
        return 'foobar'
    
    def bar():
        return foo()
    
    def baz():
        return bar()
    
    def fizz():
        return baz()
    
    fizz()
    

    输出是

    level :             module             : name
    --------------------------------------------------
        3 :              None              : fizz
        2 :              None              : baz
        1 :              None              : bar
        0 :            __main__            : foo
    
        6
  •  1
  •   Michael Swartz    8 年前

    我找到了一种方法,如果你要跨越类并且想要方法所属的类和方法。它需要一点提取工作,但它表明了自己的观点。这在Python2.7.13中有效。

    import inspect, os
    
    class ClassOne:
        def method1(self):
            classtwoObj.method2()
    
    class ClassTwo:
        def method2(self):
            curframe = inspect.currentframe()
            calframe = inspect.getouterframes(curframe, 4)
            print '\nI was called from', calframe[1][3], \
            'in', calframe[1][4][0][6: -2]
    
    # create objects to access class methods
    classoneObj = ClassOne()
    classtwoObj = ClassTwo()
    
    # start the program
    os.system('cls')
    classoneObj.method1()
    
        7
  •  -1
  •   Mohammad Shahid Siddiqui    7 年前
    #!/usr/bin/env python
    import inspect
    
    called=lambda: inspect.stack()[1][3]
    
    def caller1():
        print "inside: ",called()
    
    def caller2():
        print "inside: ",called()
    
    if __name__=='__main__':
        caller1()
        caller2()
    shahid@shahid-VirtualBox:~/Documents$ python test_func.py 
    inside:  caller1
    inside:  caller2
    shahid@shahid-VirtualBox:~/Documents$