해당 함수 내에서 함수 이름 결정(트레이스백을 사용하지 않음)
Python을 하지 않고traceback
모듈, 해당 기능 내에서 기능 이름을 결정할 수 있는 방법이 있습니까?
를 들어 '모듈이 '고 해 주세요.foo
bar
실 · 시foo.bar()
에 방법이 요?bar
bar
의 이름 름 ? 더 것은은은 '?foo.bar
의 이름 름?
#foo.py
def bar():
print "my name is", __myname__ # <== how do I calculate this at runtime?
import inspect
def foo():
print(inspect.stack()[0][3])
print(inspect.stack()[1][3]) # will give the caller of foos name, if something called foo
foo()
출력:
foo <module_caller_of_foo>
Python은 함수 자체에 있는 함수나 그 이름에 액세스할 수 있는 기능이 없습니다.그것은 제안되었지만 거절당했다.스택을 직접 가지고 놀지 않으려면 다음 중 하나를 사용해야 합니다."bar"
★★★★★★★★★★★★★★★★★」bar.__name__
문맥에 따라 다릅니다.
지정된 거부 통지는 다음과 같습니다.
이 PEP는 거부되었습니다.엣지 케이스에서 구현 방법이나 정확한 의미론은 명확하지 않으며, 중요한 사용 사례도 충분하지 않습니다.잘해야 반응이 미온적이다.
같은 결과를 얻을 수 있는 방법은 몇 가지 있습니다.
import sys
import inspect
def what_is_my_name():
print(inspect.stack()[0][0].f_code.co_name)
print(inspect.stack()[0][3])
print(inspect.currentframe().f_code.co_name)
print(sys._getframe().f_code.co_name)
에 주의:inspect.stack
은른
$ python -m timeit -s 'import inspect, sys' 'inspect.stack()[0][0].f_code.co_name'
1000 loops, best of 3: 499 usec per loop
$ python -m timeit -s 'import inspect, sys' 'inspect.stack()[0][3]'
1000 loops, best of 3: 497 usec per loop
$ python -m timeit -s 'import inspect, sys' 'inspect.currentframe().f_code.co_name'
10000000 loops, best of 3: 0.1 usec per loop
$ python -m timeit -s 'import inspect, sys' 'sys._getframe().f_code.co_name'
10000000 loops, best of 3: 0.135 usec per loop
업데이트 8/2021 (원래 게시물은 Python2.7용으로 작성되었습니다)
Python 3.9.1 (default, Dec 11 2020, 14:32:07)
[GCC 7.3.0] :: Anaconda, Inc. on linux
python -m timeit -s 'import inspect, sys' 'inspect.stack()[0][0].f_code.co_name'
500 loops, best of 5: 390 usec per loop
python -m timeit -s 'import inspect, sys' 'inspect.stack()[0][3]'
500 loops, best of 5: 398 usec per loop
python -m timeit -s 'import inspect, sys' 'inspect.currentframe().f_code.co_name'
2000000 loops, best of 5: 176 nsec per loop
python -m timeit -s 'import inspect, sys' 'sys._getframe().f_code.co_name'
5000000 loops, best of 5: 62.8 nsec per loop
functionNameAsString = sys._getframe().f_code.co_name
코드의 여러 위치에 있는 로그 문자열에 함수 이름을 넣고 싶었기 때문에 비슷한 것을 원했습니다.그렇게 하는 것이 가장 좋은 방법은 아닐 수도 있지만, 현재 함수의 이름을 얻는 방법은 다음과 같습니다.
@Andreas Jung이 나타내는 접근방식을 사용하여 정의된 이름을 얻을 수 있지만 함수가 호출된 이름이 아닐 수 있습니다.
import inspect
def Foo():
print inspect.stack()[0][3]
Foo2 = Foo
>>> Foo()
Foo
>>> Foo2()
Foo
그 구별이 당신에게 중요한지 아닌지 나는 말할 수 없다.
이 편리한 유틸리티를 근처에 두고 있습니다.
import inspect
myself = lambda: inspect.stack()[1][3]
사용방법:
myself()
, 아, 아, 맞다.inspect
가장 좋은 방법이라고 생각합니다.예를 들어 다음과 같습니다.
import inspect
def bar():
print("My name is", inspect.stack()[0][3])
함수 이름을 적어줄 포장지를 찾았습니다.
from functools import wraps
def tmp_wrap(func):
@wraps(func)
def tmp(*args, **kwargs):
print func.__name__
return func(*args, **kwargs)
return tmp
@tmp_wrap
def my_funky_name():
print "STUB"
my_funky_name()
이것은 인쇄됩니다.
my_funky_name
스터브
이것은 실제로 질문에 대한 다른 답변에서 파생되었습니다.
제 생각은 이렇습니다.
import sys
# for current func name, specify 0 or no argument.
# for name of caller of current func, specify 1.
# for name of caller of caller of current func, specify 2. etc.
currentFuncName = lambda n=0: sys._getframe(n + 1).f_code.co_name
def testFunction():
print "You are in function:", currentFuncName()
print "This function's caller was:", currentFuncName(1)
def invokeTest():
testFunction()
invokeTest()
# end of file
inspect.stack()을 사용하는 것보다 이 버전이 더 빠를 수 있습니다(시스템 사용에 관한 Alex Melihoff의 투고 및 타이밍 참조)._getframe()과 inspect.stack()을 비교합니다.
print(inspect.stack()[0].function)
피톤 3.5.
나는 왜 사람들이 그것을 복잡하게 만드는지 모르겠다.
import sys
print("%s/%s" %(sys._getframe().f_code.co_filename, sys._getframe().f_code.co_name))
미래에도 대비할 수 있는 접근방식은 다음과 같습니다.
@CamHart 및 @Yuval의 제안과 @RoshOxymoron이 인정하는 답변을 조합하면 다음을 피할 수 있습니다.
_hidden
되지 않을 수 있는- (미래의 비단뱀에서 순서를 변경할 수 있는) 스택에 색인화
따라서 향후 Python 버전(2.7.3 및 3.3.2에서 테스트 완료)에 적합하다고 생각합니다.
from __future__ import print_function
import inspect
def bar():
print("my name is '{}'".format(inspect.currentframe().f_code.co_name))
업데이트: 3.7.10, 3.8.10 및 3.9.5에서 테스트 완료
import inspect
def whoami():
return inspect.stack()[1][3]
def whosdaddy():
return inspect.stack()[2][3]
def foo():
print "hello, I'm %s, daddy is %s" % (whoami(), whosdaddy())
bar()
def bar():
print "hello, I'm %s, daddy is %s" % (whoami(), whosdaddy())
foo()
bar()
IDE의 코드 출력
안녕, 난 foo, 아빠는
안녕, 난 술집이야, 아빠는 푸
안녕, 난 술집이야, 아빠는
import sys
def func_name():
"""
:return: name of caller
"""
return sys._getframe(1).f_code.co_name
class A(object):
def __init__(self):
pass
def test_class_func_name(self):
print(func_name())
def test_func_name():
print(func_name())
테스트:
a = A()
a.test_class_func_name()
test_func_name()
출력:
test_class_func_name
test_func_name
__name__
★★★★
# foo.py
def bar():
print(f"my name is {bar.__name__}")
에 쉽게 할 수 .__name__
여하하다
>>> def bar():
... print(f"my name is {bar.__name__}")
...
>>> bar()
my name is bar
나는 이 질문을 할 방법을 찾으면서 여러 번 이 질문을 접했다.정답은 Python의 설명서에 나와 있습니다(콜 가능 유형 섹션 참조).
에는 ""가 .__name__
및 '''를 반환하는 파라미터__qualname__
소속 클래스를 포함하여 전체 이름을 반환하는 매개 변수입니다(수식 이름 참조).
데코레이터를 사용할 수 있습니다.
def my_function(name=None):
return name
def get_function_name(function):
return function(name=function.__name__)
>>> get_function_name(my_function)
'my_function'
데코레이터를 사용하면 쉽게 할 수 있습니다.
>>> from functools import wraps
>>> def named(func):
... @wraps(func)
... def _(*args, **kwargs):
... return func(func.__name__, *args, **kwargs)
... return _
...
>>> @named
... def my_func(name, something_else):
... return name, something_else
...
>>> my_func('hello, world')
('my_func', 'hello, world')
스택 요소에 의존하지 않는 것이 좋습니다.다른 컨텍스트 내에서 코드를 사용하는 경우(예를 들어 python 인터프리터) 스택이 변경되어 인덱스([0][3])가 해제됩니다.
나는 너에게 그런 것을 추천한다:
class MyClass:
def __init__(self):
self.function_name = None
def _Handler(self, **kwargs):
print('Calling function {} with parameters {}'.format(self.function_name, kwargs))
self.function_name = None
def __getattr__(self, attr):
self.function_name = attr
return self._Handler
mc = MyClass()
mc.test(FirstParam='my', SecondParam='test')
mc.foobar(OtherParam='foobar')
다중 상속 시나리오에서 안전하게 슈퍼를 호출할 때 사용하는 독자적인 접근법(모든 코드를 입력)
def safe_super(_class, _inst):
"""safe super call"""
try:
return getattr(super(_class, _inst), _inst.__fname__)
except:
return (lambda *x,**kx: None)
def with_name(function):
def wrap(self, *args, **kwargs):
self.__fname__ = function.__name__
return function(self, *args, **kwargs)
return wrap
사용 예:
class A(object):
def __init__():
super(A, self).__init__()
@with_name
def test(self):
print 'called from A\n'
safe_super(A, self)()
class B(object):
def __init__():
super(B, self).__init__()
@with_name
def test(self):
print 'called from B\n'
safe_super(B, self)()
class C(A, B):
def __init__():
super(C, self).__init__()
@with_name
def test(self):
print 'called from C\n'
safe_super(C, self)()
테스트:
a = C()
a.test()
출력:
called from C
called from A
called from B
각 @with_name 데코레이션 메서드 내에서는 자신에 대한 접근권이 있습니다.__fname__는 현재 함수 이름입니다.
최근 위의 답변을 사용하여 해당 함수의 컨텍스트에서 함수의 docstring에 액세스하려고 했지만 위의 질문들은 이름 문자열만 반환하기 때문에 작동하지 않았습니다.
다행히 간단한 해결책을 찾았습니다.저와 마찬가지로 단순히 함수 이름의 문자열에 적용할 수 있는 eval()을 나타내는 문자열을 얻는 것이 아니라 함수를 참조하는 것입니다.
import sys
def foo():
"""foo docstring"""
print(eval(sys._getframe().f_code.co_name).__doc__)
sys._getframe().f_back.f_code.co_name
python 3.9에서는 전혀 동작하지 않습니다.다음은 사용할 수 있습니다.
from inspect import currentframe
def testNameFunction() -> str:
return currentframe().f_back.f_code.co_name
print(f'function name is {testNameFunction()}(...)')
결과:
function name is testNameFunction(...)
데코레이터를 사용하는 것은 좋지만 함수 인수에 손을 대지 않는 것이 좋습니다.그래서 또 다른 대안을 제시하겠습니다.
import functools
def withname(f):
@functools.wraps(f)
def wrapper(*args, **kwargs):
global __name
__saved_name = globals().get("__name")
__name = f.__name__
ret = f(*args, **kwargs)
__name = __saved_name
return ret
return wrapper
@withname
def f():
print(f"in f: __name=={__name}")
g()
print(f"back in f: __name=={__name}")
@withname
def g():
print(f"in g: __name=={__name}")
과 복원이 합니다.__name
이 함수는 글로벌 변수이기 때문에 호출됩니다. " "f()
위의 제품:
in f: __name==f
in g: __name==g
back in f: __name==f
유감스럽게도, 다른 방법은 없습니다.global
변수(function 인수를 변경하지 않을 경우)를 지정합니다.함수의 컨텍스트에서 생성되지 않은 변수를 참조하면 글로벌 변수를 검색하는 코드가 생성됩니다.
>>> def f(): print(__function__)
>>> from dis import dis
>>> dis(f)
1 0 LOAD_GLOBAL 0 (print)
2 LOAD_GLOBAL 1 (__function__)
4 CALL_FUNCTION 1
6 POP_TOP
8 LOAD_CONST 0 (None)
10 RETURN_VALUE
str(str(inspect.currentframe())).split(' ')[-1][:-1]
import inspect
def method_name():
return inspect.stack()[1][3]
def method_name_caller():
return inspect.stack()[2][3]
def asdf():
print(method_name_caller())
print(method_name())
def asdf2():
print(method_name_caller())
print(method_name())
asdf()
@http-laughlin의 대답은 아름답다.제가 생각하기에 의도라고 생각되는 기능 실행을 추적하고 인수 목록과 키워드 인수를 캡처하기 위해 약간 수정했습니다.감사합니다 @jeff-laughlin!
from functools import wraps
import time
def named(func):
@wraps(func)
def _(*args, **kwargs):
print(f"From wrapper function: Executing function named: {func.__name__}, with arguments: {args}, and keyword arguments: {kwargs}.")
print(f"From wrapper function: {func}")
start_time = time.time()
return_value = func(*args, **kwargs)
end_time = time.time()
elapsed_time = end_time - start_time
print(f"From wrapper function: Execution of {func.__name__} took {elapsed_time} seconds.")
return return_value
return _
@named
def thanks(message, concepts, username='@jeff-laughlin'):
print(f"From inner function: {message} {username} for teaching me about the {concepts} concepts of closures and decorators!")
thanks('Thank you', 'two', username='@jeff-laughlin')
print('-'*80)
thanks('Thank you', 'two', username='stackoverflow')
print(thanks)
래퍼 기능에서:함수 이름: thanks('감사합니다', 'two') 및 키워드 인수 {'username': '@jeff-laughlin'}을(를) 사용하여 실행합니다.
래퍼 기능에서 : <0x7f13e6ceaa60에서의 기능 감사>
내부 기능에서:클로저와 데코레이터의 두 가지 컨셉에 대해 가르쳐 주셔서 @jeff-laughlin!
래퍼 기능에서:감사의 실행에는 2.193450927734375e-05초가 소요되었습니다.
--------------------------------------------------------------------------------
래퍼 기능에서:함수 이름: thanks('감사합니다', '2') 및 키워드 인수: {'username': 'stack overflow'}를 사용하여 함수를 실행합니다.
래퍼 기능에서 : <0x7f13e6ceaa60에서의 기능 감사>
와 데코레이터의 주셔서 합니다.클로저와 데코레이터의 두 가지 컨셉에 대해 가르쳐 주셔서 감사합니다.
은 7.7.152557373046875e-06번지
at 0x7f13e6ceaca0 <0x7f13e6ceaca0>
가장 놀라운 것은 실행 시 함수를 가로채고 검사하여 이를 바탕으로 몇 가지 조치를 취할 수 있는 방법이 있다는 것입니다.또 다른 놀라운 점은 내부 기능의 메모리 주소가 두 번 모두 같다는 것입니다.왜 그런지 아는 사람 있어요?이 데코레이터/클로저 마법을 이해하려면 아직 가야 할 길이 있습니다.
의 모든 , 이 문장이 되고 있는 것.inspect
도서관, 모두 다음과 같은 글을 쓰고 있습니다.
import inspect
inspect.stack()[0][3]
단, 의 반환은 Named이므로폼의 태플:
FrameInfo(frame=<frame at 0x103578810, file '<stdin>', line 1, code <module>>, filename='<stdin>', lineno=1, function='<module>', code_context=None, index=None)
이름만 부르면 된다.
여기서 작은 더미의 예를 볼 수 있습니다.
def test_train_UGRIZY_noZ(self, architecture, dataset, hyperrun, wloss):
log.warning(f"{inspect.stack()[0].function} -- Not Implemented Yet")
pass
실행 시 인쇄:
WARNING - test_train_UGRIZY_noZ -- Not Implemented Yet
언급URL : https://stackoverflow.com/questions/5067604/determine-function-name-from-within-that-function-without-using-traceback
'itsource' 카테고리의 다른 글
pip을 사용하여 Python MySQLdb 모듈을 설치하는 방법 (0) | 2022.09.17 |
---|---|
텍스트 파일에서 mysql 데이터베이스로 데이터를 가져오는 방법 (0) | 2022.09.17 |
Java에서 긴 정수를 구분 없이 문자열로 포맷하려면 어떻게 해야 합니까? (0) | 2022.09.17 |
Python 문자열에서 마지막 구분 기호로 분할하시겠습니까? (0) | 2022.09.17 |
목록을 반복하는 것이 목록을 통해 인덱싱하는 것보다 더 빠른 이유는 무엇입니까? (0) | 2022.09.16 |