답변:
파이썬에는 함수 자체 내에서 함수 또는 그 이름에 액세스하는 기능이 없습니다. 제안 되었지만 거부 되었습니다 . 스택을 직접 사용하고 싶지 않은 경우 컨텍스트에 따라 사용 "bar"
하거나 사용해야합니다 bar.__name__
.
주어진 거부 통지는 다음과 같습니다.
이 PEP는 거부됩니다. 어떻게 구현해야하는지 또는 정확한 경우 의미론이 무엇인지 명확하지 않으며, 중요한 사용 사례가 충분하지 않습니다. 응답은 기껏해야 미지근했습니다.
inspect.currentframe()
그런 방법 중 하나입니다.
print(inspect.currentframe().f_code.co_name)
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
[1][3]
발신자의 이름을 얻을 수도 있기 때문에 좋습니다 .
print(inspect.currentframe().f_code.co_name)
또는을 사용 하여 발신자의 이름을 얻을 수도 있습니다 print(inspect.currentframe().f_back.f_code.co_name)
. 모든 스택 프레임 목록을 검색하지 않기 때문에 더 빠를 것이라고 생각합니다 inspect.stack()
.
inspect.currentframe().f_back.f_code.co_name
반면이 장식 된 방법으로 작동하지 않습니다 inspect.stack()[0][3]
않습니다 ...
동일한 결과를 얻는 몇 가지 방법이 있습니다.
from __future__ import print_function
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
inspect.currentframe()
실행 시간과 개인 멤버의 사용 사이에 좋은 트레이드 오프 인 것 같습니다
0.100 usec
나 0.199 usec
있지만, 어느 쪽이든 - 빠른 (안토니 Hatchkins 옵션 4보다 옵션 3 세 배 빠른 발견하지만) 옵션 4와 비교 옵션 1, 2보다 수백 배.
sys._getframe().f_code.co_name
동안 inspect.currentframe().f_code.co_name
나는 이미 가져온 간단하기 때문에 sys
모듈을. 합리적인 결정입니까? (속도를 고려하면 상당히 비슷 함)
@Andreas Jung이 보여주는 접근 방식을 사용하여 정의 된 이름을 얻을 수 있지만 함수가 호출 된 이름이 아닐 수도 있습니다.
import inspect
def Foo():
print inspect.stack()[0][3]
Foo2 = Foo
>>> Foo()
Foo
>>> Foo2()
Foo
그 구별이 당신에게 중요한지 아닌지는 말할 수 없습니다.
.func_name
. 파이썬에서 클래스 이름과 함수 이름은 기억해야 할 것이 있고 그것들을 참조하는 변수는 다른 것입니다.
Foo2()
인쇄 하고 싶을 수도 있습니다 Foo
. 예를 들면 다음과 같습니다 Foo2 = function_dict['Foo']; Foo2()
.. 이 경우 Foo2는 아마도 명령 행 구문 분석기의 함수 포인터입니다.
functionNameAsString = sys._getframe().f_code.co_name
함수 이름을 코드의 여러 위치에있는 로그 문자열에 넣고 싶었 기 때문에 매우 비슷한 것을 원했습니다. 아마도 가장 좋은 방법은 아니지만 현재 함수의 이름을 얻는 방법이 있습니다.
f
프레임과 co
코드 를 염두 에 두겠습니다 . 난 그냥 일부 발췌 문장에서 저장하면 더 잘 사용하지 않습니다 :-)
이 편리한 유틸리티를 근처에 둡니다.
import inspect
myself = lambda: inspect.stack()[1][3]
용법:
myself()
함수 이름을 쓸 래퍼를 찾았습니다.
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
그루터기
my_funky_name.__name__
입니다. func .__ name__을 새 매개 변수로 함수에 전달할 수 있습니다. func (* args, ** kwargs, my_name = func .__ name__). 함수 내부에서 데코레이터 이름을 얻으려면 inspect를 사용해야한다고 생각합니다. 그러나 내 실행중인 기능 내에서 내 기능을 제어하는 기능의 이름을 얻는 것 ... ... 아름다운 meme의 시작과 같은 소리 :)
이것은 실제로 질문에 대한 다른 답변에서 파생됩니다.
여기 내 테이크가있다 :
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 ()을 사용하는 것보다이 버전의 장점은 수천 배나 빨라야한다는 것입니다 [apps.stack () 사용과 비교하여 Alex Melihoff의 포스트 및 sys._getframe () 사용에 대한 타이밍 참조].
미래에 대비할 수있는 방법이 있습니다.
@CamHart와 @Yuval의 제안을 @RoshOxymoron의 승인 된 답변 과 결합하면 다음을 피할 수 있습니다.
_hidden
잠재적으로 사용되지 않는 방법그래서 이것은 미래의 파이썬 버전 (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))
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
사람들이 왜 그것을 복잡하게하는지 모르겠습니다.
import sys
print("%s/%s" %(sys._getframe().f_code.co_filename, sys._getframe().f_code.co_name))
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에서 코드 출력
안녕, 난 바보 야 아빠는
안녕, 난 바야, 아빠는 바보 야
안녕, 난 바야, 아빠는
데코레이터를 사용할 수 있습니다 :
def my_function(name=None):
return name
def get_function_name(function):
return function(name=function.__name__)
>>> get_function_name(my_function)
'my_function'
__name__
함수 의 속성 을 얻는 복잡한 방법처럼 보입니다 . 사용법은 얻고 자하는 것을 알아야합니다. 기능이 즉시 정의되지 않은 간단한 경우에는 나에게 유용하지 않습니다.
다중 상속 시나리오 내에서 안전을 사용하여 super를 호출하는 데 사용되는 자체 접근법을 사용합니다 (모든 코드를 넣습니다)
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 장식 메소드 내에서 현재 함수 이름으로 self .__ fname__에 액세스 할 수 있습니다.
스택 요소에 의존하지 않는 것이 좋습니다. 다른 컨텍스트에서 코드를 사용하는 경우 (예 : 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')
이것은 데코레이터로 달성하기가 매우 쉽습니다.
>>> 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')
traceback
입니다. 답과 의견의 시대조차도 그것을 뒷받침하지 않는 것 같습니다.