Определить имя функции из этой функции (без использования traceback) - PullRequest
382 голосов
/ 21 февраля 2011

В Python, без использования модуля traceback, есть ли способ определить имя функции из этой функции?

Скажем, у меня есть модуль foo с функциональной панелью.При выполнении foo.bar() есть ли способ, чтобы бар узнал имя бара?Или еще лучше, имя foo.bar?

#foo.py  
def bar():
    print "my name is", __myname__ # <== how do I calculate this at runtime?

Ответы [ 20 ]

10 голосов
/ 16 октября 2015
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

привет, я бар, папа

9 голосов
/ 22 октября 2016
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
9 голосов
/ 18 марта 2015

Вот подход, ориентированный на будущее.

Сочетание предложений @ CamHart's и @ 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))
7 голосов
/ 29 апреля 2015

Вы можете использовать декоратор:

def my_function(name=None):
    return name

def get_function_name(function):
    return function(name=function.__name__)

>>> get_function_name(my_function)
'my_function'
5 голосов
/ 11 мая 2017

Я сделал то, что сказал CamHart:

import sys
def myFunctionsHere():
    print(sys._getframe().f_code.co_name)

myFunctionsHere()

Вывод:

C: \ Python \ Python36 \ python.exe C: /Python/GetFunctionsNames/TestFunctionsNames.py myFunctionsHere

Процесс завершен с кодом выхода 0

3 голосов
/ 13 сентября 2018

Недавно я попытался использовать приведенные выше ответы для доступа к строке документации функции из контекста этой функции, но поскольку в приведенных выше вопросах возвращалась только строка имени, она не работала.простое решение.Если, как и я, вы хотите обратиться к функции, а не просто получить строку, представляющую имя, которое вы можете применить eval () к строке имени функции.

import sys
def foo():
    """foo docstring"""
    print(eval(sys._getframe().f_code.co_name).__doc__)
3 голосов
/ 26 августа 2018

Используйте это (основываясь на ответе Рона Дэвиса):

import sys

def thisFunctionName():
    """Returns a string with the name of the function it's called from"""
    return sys._getframe(1).f_code.co_name
3 голосов
/ 24 декабря 2015

Я использую свой собственный подход для вызова 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()

выход: * +1010 *

called from C
called from A
called from B

Внутри каждого украшенного метода @with_name у вас есть доступ к self .__ fname__ в качестве текущего имени функции.

2 голосов
/ 03 мая 2019

Я предлагаю не полагаться на элементы стека. Если кто-то использует ваш код в разных контекстах (например, интерпретатор 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')
0 голосов
/ 10 июля 2019

Я не уверен, почему люди усложняют:

import sys 
print("%s/%s" %(sys._getframe().f_code.co_filename, sys._getframe().f_code.co_name))
...