programing

호출된 메서드에서 발신자의 메서드 이름을 가져오려면 어떻게 해야 합니까?

javaba 2022. 10. 7. 23:34
반응형

호출된 메서드에서 발신자의 메서드 이름을 가져오려면 어떻게 해야 합니까?

Python: 호출된 메서드에서 호출자의 메서드 이름을 가져오려면 어떻게 해야 합니까?

두 가지 방법이 있다고 가정합니다.

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

def method2(self):
    ...

method1을 변경하지 않을 경우 method2에서 발신자 이름(이 예에서는 method1)을 취득하려면 어떻게 해야 합니까?

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

이 자기성찰은 디버깅과 개발을 지원하기 위한 것입니다.실가동 기능의 목적으로는 사용하지 않는 것이 좋습니다.

단축판:

import inspect

def f1(): f2()

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

f1()

(@Alex와 Stefaan Lippen에게 감사하며)

이것은 정상적으로 동작하고 있는 것 같습니다.

import sys
print sys._getframe().f_back.f_code.co_name

를 사용합니다.주로 다음 세 가지 유형 중 하나로 구성된 이전 답변에서는 이 사용법에 대해 다루지 않았습니다.

  • 일부 선행 응답은 다음과 같이 사용됩니다.inspect.stack속도가 너무 느린 것으로 알려져 있습니다.
  • 일부 선행 응답은 다음과 같이 사용됩니다.sys._getframe이 함수는 선두에 밑줄이 있는 내부 프라이빗 함수이므로 그 사용은 암묵적으로 권장되지 않습니다.
  • 1개의 선행답변은 다음과 같습니다.inspect.getouterframes(inspect.currentframe(), 2)[1][3]하지만 뭐가 뭔지 전혀 알 수 없다.[1][3]접속하고 있습니다.
import inspect
from types import FrameType
from typing import cast


def demo_the_caller_name() -> str:
    """Return the calling function's name."""
    # Ref: https://stackoverflow.com/a/57712700/
    return cast(FrameType, cast(FrameType, inspect.currentframe()).f_back).f_code.co_name


if __name__ == '__main__':
    def _test_caller_name() -> None:
        assert demo_the_caller_name() == '_test_caller_name'
    _test_caller_name()

주의:cast(FrameType, frame)를 만족시키기 위해 사용됩니다.mypy.


확인: 답변에 대한 1313e의 코멘트.

모듈 및 클래스를 포함한 완전한 메서드 이름을 구축하기 위해 약간 더 긴 버전을 생각해냈습니다.

https://gist.github.com/2151727 (rev 9ccbf)

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

위에 있는 것들이 약간 합쳐진 것 같아.하지만 내 특기는 이거야.

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

데코레이터를 사용할 수 있으며 스택 트레이스를 사용할 필요가 없습니다.

클래스 내에서 메서드를 꾸미려면

import functools

# outside ur class
def printOuterFunctionName(func):
@functools.wraps(func)
def wrapper(self):
    print(f'Function Name is: {func.__name__}')
    func(self)    
return wrapper 

class A:
  @printOuterFunctionName
  def foo():
    pass

제거할 수 있습니다.functools,self절차상으로는

여러 클래스에 걸쳐서 메서드가 속한 클래스와 메서드를 원하는 경우 방법을 찾았습니다.약간의 추출 작업이 필요하지만 요점을 알 수 있다.이것은 Python 2.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()

코드:

#!/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$

대신 Python의 Logging 라이브러리에서 발신자 정보를 검색합니다.아이디어는 다음과 같습니다.

  1. 예외를 제기하다

  2. 예외조항으로 즉시 이해하다.

  3. 를 사용하여 트레이스백프레임을 가져옵니다(tb_frame).

  4. 부터tb_frame를 사용하여 마지막 발신자의 프레임을 취득f_back.

  5. 마지막 발신자 프레임에서 실행되고 있던 코드 오브젝트를 가져옵니다.

    샘플 코드에서는 다음과 같습니다.method1(없음)method2)가 실행되고 있습니다.

  6. 취득한 코드 오브젝트에서 오브젝트의 이름을 가져옵니다.이것은 샘플에 있는 발신자 메서드의 이름입니다.

다음은 질문의 예를 해결하기 위한 샘플 코드입니다.

def method1():
    method2()

def method2():
    try:
        raise Exception
    except Exception:
        frame = sys.exc_info()[2].tb_frame.f_back

    print("method2 invoked by: ", frame.f_code.co_name)

# Invoking method1
method1()

출력:

method2 invoked by: method1

프레임에는 행 번호, 파일 이름, 인수 수, 인수 유형 등 모든 종류의 세부 정보가 포함됩니다.솔루션은 클래스 및 모듈 전체에서도 작동합니다.

이봐, 내가 예전에 내 앱에 플러그인 없이 3가지 방법을 만들었는데, 그게 너에게 도움이 될 수도 있어. 나한테도 효과가 있었으니까, 너한테도 효과가 있을지도 몰라.

def method_1(a=""):
    if a == "method_2":
        print("method_2")

    if a == "method_3":
        print("method_3")


def method_2():
    method_1("method_2")


def method_3():
    method_1("method_3")


method_2()

언급URL : https://stackoverflow.com/questions/2654113/how-to-get-the-callers-method-name-in-the-called-method

반응형