함수 이름을 문자열로 얻는 방법?


740

파이썬에서 함수를 호출하지 않고 어떻게 함수 이름을 문자열로 얻습니까?

def my_function():
    pass

print get_function_name_as_string(my_function) # my_function is not in quotes

출력해야합니다 "my_function".

파이썬에서 그러한 기능을 사용할 수 있습니까? 그렇지 않다면 get_function_name_as_string파이썬에서 구현 방법에 대한 아이디어가 있습니까?


답변:


944
my_function.__name__

사용은 __name__균일하게 적용되는 바람직한 방법이다. 와 달리 func_name내장 함수에서도 작동합니다.

>>> import time
>>> time.time.func_name
Traceback (most recent call last):
  File "<stdin>", line 1, in ?
AttributeError: 'builtin_function_or_method' object has no attribute 'func_name'
>>> time.time.__name__ 
'time'

또한 이중 밑줄은 독자에게 이것이 특별한 속성임을 나타냅니다. 보너스로 클래스와 모듈에도 __name__속성이 있으므로 하나의 특별한 이름 만 기억합니다.


420
어떤 경우에는 함수에 대한 인수로 함수 객체를 얻으므로 해당 함수의 이름을 표시 / 저장 / 조작해야합니다. 아마도 문서, 도움말 텍스트, 작업 내역 등을 생성하고있을 수 있습니다. 따라서 함수 이름을 하드 코딩하는 것은 아닙니다.
mbargiel

2
@ mgargiel : 내가 말하고자하는 것은 100 개의 메소드를 정의하는 클래스를 가지고 있다고 가정합니다. 모든 메소드는 랩퍼 일뿐이며 개인 메소드를 호출하고 랩퍼 자체의 이름을 전달합니다. 이와 같은 것 : def wrapper(kwargs): super(ExtendedClass,self).call('wrapper', kwargs). 다른 선택 사항이 def wrapper(kwargs): super(ExtendedClass,self).call(sys._getframe().f_code.co_name, kwargs)있습니다. Albert Vonpupp의 답변이 나에게 더 좋습니다.
Richard Gomes

19
@RichardGomes 하나의 답변은 함수 자체에서 이름을 얻는 데 적합하고 다른 하나는 함수 참조에서 가져 오는 데 적합합니다. 작성된 OP의 질문은 후자를 나타냅니다.
Russell Borogove가

22
@RichardGomes 사실 나는이 문제에 대한 해결책을 찾고있는이 질문에 왔습니다. 내가 해결하려는 문제는 모든 통화를 기록하는 데 사용할 수있는 데코레이터를 만드는 것입니다.
ali-hussain

23
@RichardGomes 함수는 일류 객체이며, 그 이상의 이름을 가질 수 있습니다. 반드시 그런 것은 아닙니다 f.__name__ == 'f'.
wim

298

현재 함수 또는 메소드 이름을 내부에서 가져 오려면 다음을 고려하십시오.

import inspect

this_function_name = inspect.currentframe().f_code.co_name

sys._getframeinspect.currentframe후자는 개인 기능에 대한 액세스를 피하지만 대신 작동 합니다.

대신 호출 함수의 이름을 얻으려면 다음 f_back과 같이 고려하십시오 inspect.currentframe().f_back.f_code.co_name.


를 사용하는 경우 다음 mypy과 같이 불평 할 수 있습니다.

오류 : "선택 사항 [FrameType]"의 "없음"항목에 "f_code"속성이 없습니다.

위의 오류를 억제하려면 다음을 고려하십시오.

import inspect
import types
from typing import cast

this_function_name = cast(types.FrameType, inspect.currentframe()).f_code.co_name

45
+1 :이 답을보고 싶습니다. 다른 답변은 호출자가 이미이 질문의 맥락에서 의미가없는 함수 이름을 알고 있다고 가정합니다.
Richard Gomes

110
리차드 : 아닙니다. 함수가 정의한 것과 동일한 범위에서 직접 name 또는 func_name을 호출한다고 가정하고 있습니다 . 함수는 객체라는 것을 명심하십시오. 그것들은 다른 함수에 대한 인수로 전달 될 수 있으며, 나중에 조회 또는 실행 등에 대한 목록 / dicts에 저장 될 수 있습니다.
mbargiel

11
@paulus_almighty, 스택 프레임을 파고 들더라도 추상적 인 느낌이 들지 않습니다! 사실, 그것은 추상과 반대입니다. 문서 의 구현 세부 사항 노트를 참조하십시오 . 모든 Python 구현에 포함되는 것은 아닙니다 sys._getframe. CPython의 내부에 직접 연결되어 있습니다.
senderle

6
이것은 함수 내에서만 작동하지만 질문은 함수를 호출해서는 안된다는 것을 지정합니다.
user2357112는 Monica

5
함수를보다 유용하고 기억하기 쉬운 것으로 감싸고 싶다면 프레임 1과 같은 것을 검색해야 sys._getframe(1).f_code.co_name하므로 함수를 정의하고 get_func_name()호출 한 함수의 원하는 이름을 얻을 수 있습니다.
m3nda

44
my_function.func_name

함수의 다른 재미있는 속성도 있습니다. 입력 dir(func_name)하여 입력 하십시오. func_name.func_code.co_code컴파일 된 함수이며 문자열로 저장됩니다.

import dis
dis.dis(my_function)

의 코드가 표시됩니다 거의 사람이 읽을 수있는 형식을. :)


4
f .__ name__과 f.func_name의 차이점은 무엇입니까?
Federico A. Ramponi

14
샘 : 이름은 비공개이고 __ 이름은 특별합니다. 개념적 차이가 있습니다.
Matthew Trevor

11
누군가가 Matthew의 이전 답변에 당황한 경우 주석 시스템은 일부 이중 밑줄을 굵은 체로 해석했습니다. 백틱으로 이스케이프 된 메시지는 다음 __names__과 같이 읽어야 __names합니다.
gwideman

12
실제로, 나는 올바른 것이 _names개인 (전의 밑줄, 컨벤션), __names__특별 함 (앞뒤의 이중 밑줄 ) 이라고 생각합니다 . 이전에 이중 밑줄이 공식적으로 또는 규칙으로 의미가 있는지 확실하지 않습니다.
MestreLion

8
func_namepython3에는 더 이상 존재하지 않으므로 func.__name__호환성을 원한다면 사용해야 합니다
Daenyth

34

이 함수는 호출자의 함수 이름을 반환합니다.

def func_name():
    import traceback
    return traceback.extract_stack(None, 2)[0][2]

친절한 래퍼에 대한 Albert Vonpupp의 답변과 같습니다.


1
인덱스 [2]에 "<모듈>"이 있었지만 다음과 같이 작동했습니다. traceback.extract_stack (None, 2) [0] [-1]
emmagras

3
나를 위해 이것은 작동하지 않지만 이것은 작동합니다 : traceback.extract_stack () [-1] [2]
mike01010

이것은 첫 번째 인덱스를 1로 변경하면 작동하기 전에 주석을 달기 전에 디버그하는 법을 배워야합니다 ... traceback.extract_stack (None, 2) [1] [2]
Jcc.Sanabria

29

클래스 메소드에 관심이 있다면 Python 3.3 이상 __qualname__에 추가하십시오 __name__.

def my_function():
    pass

class MyClass(object):
    def method(self):
        pass

print(my_function.__name__)         # gives "my_function"
print(MyClass.method.__name__)      # gives "method"

print(my_function.__qualname__)     # gives "my_function"
print(MyClass.method.__qualname__)  # gives "MyClass.method"

20

함수 데코레이터를 사용하는 것이 좋습니다. 함수 시간을 곱한 클래스를 추가했습니다. gLog가 표준 파이썬 로거라고 가정합니다.

class EnterExitLog():
    def __init__(self, funcName):
        self.funcName = funcName

    def __enter__(self):
        gLog.debug('Started: %s' % self.funcName)
        self.init_time = datetime.datetime.now()
        return self

    def __exit__(self, type, value, tb):
        gLog.debug('Finished: %s in: %s seconds' % (self.funcName, datetime.datetime.now() - self.init_time))

def func_timer_decorator(func):
    def func_wrapper(*args, **kwargs):
        with EnterExitLog(func.__name__):
            return func(*args, **kwargs)

    return func_wrapper

이제 기능과 관련된 모든 것은 장식하고 짜는 것입니다.

@func_timer_decorator
def my_func():

15

sys._getframe()파이썬의 모든 구현에서 사용 가능한 것은 아닙니다 ( ref 참조 ) traceback. 예를 들어 모듈을 사용 하여 같은 일을 할 수 있습니다 .

import traceback
def who_am_i():
   stack = traceback.extract_stack()
   filename, codeline, funcName, text = stack[-2]

   return funcName

에 대한 호출 stack[-1]은 현재 프로세스 세부 사항을 리턴합니다.


sys._getframe()정의되지 않은 경우 traceback.extract_stack에도 작동하지 않습니다. 후자는 전자의 기능에 대한 대략적인 수퍼 셋을 제공합니다. 다른 하나 없이는 하나를 볼 수 없습니다. 실제로 IronPython 2.7에서는 extract_stack()항상을 반환합니다 []. -1
SingleNegationElimination 1

15
import inspect

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

어디

  • stack () [0] 호출자

  • stack () [3] 메소드의 문자열 이름


1
평범하고 단순합니다. stack()[0]항상 [3]메소드의 문자열 이름 인 호출자가됩니다 .
kontur

14

@ Demyn 's answer 의 확장으로 현재 함수의 이름과 현재 함수의 인수를 인쇄하는 유틸리티 함수를 만들었습니다.

import inspect
import logging
import traceback

def get_function_name():
    return traceback.extract_stack(None, 2)[0][2]

def get_function_parameters_and_values():
    frame = inspect.currentframe().f_back
    args, _, _, values = inspect.getargvalues(frame)
    return ([(i, values[i]) for i in args])

def my_func(a, b, c=None):
    logging.info('Running ' + get_function_name() + '(' + str(get_function_parameters_and_values()) +')')
    pass

logger = logging.getLogger()
handler = logging.StreamHandler()
formatter = logging.Formatter(
    '%(asctime)s [%(levelname)s] -> %(message)s')
handler.setFormatter(formatter)
logger.addHandler(handler)
logger.setLevel(logging.INFO)

my_func(1, 3) # 2016-03-25 17:16:06,927 [INFO] -> Running my_func([('a', 1), ('b', 3), ('c', None)])

8

함수의 이름을 얻으려면 여기에 간단한 코드가 있습니다. 이 함수를 정의했다고 가정 해 봅시다.

def function1():
    print "function1"

def function2():
    print "function2"

def function3():
    print "function3"
print function1.__name__

출력은 function1이됩니다

이제이 기능들이 목록에 있다고 가정 해 봅시다.

a = [function1 , function2 , funciton3]

함수의 이름을 얻기 위해

for i in a:
    print i.__name__

출력은

기능 1
기능 2
기능 3


5

나는 약간의 장황한 느낌이 들었지만 데코레이터를 사용하는 몇 가지 답변을 보았습니다. 다음은 함수 이름과 해당 입력 및 출력 값을 로깅하는 데 사용하는 것입니다. 로그 파일을 작성하지 않고 정보를 인쇄하고 OP 특정 예제에 적용하도록 여기에 적용했습니다.

def debug(func=None):
    def wrapper(*args, **kwargs):
        try:
            function_name = func.__func__.__qualname__
        except:
            function_name = func.__qualname__
        return func(*args, **kwargs, function_name=function_name)
    return wrapper

@debug
def my_function(**kwargs):
    print(kwargs)

my_function()

산출:

{'function_name': 'my_function'}

1
다른 것들과 달리 내가 이것에 대해 좋아하는 것은 debug함수를 한 번만 추가하면 함수 이름을 인쇄하거나 원하는 함수에 데코레이터를 추가하여 기능을 추가 할 수 있다는 것입니다. 가장 쉽고 가장 적합한 것으로 보입니다.
spareTimeCoder
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.