2010-04-16 24 views
113

Python: cómo obtener el nombre del método de la persona que llama en el método llamado?Python: cómo obtener el nombre del método de la persona que llama en el método llamado?

Supongamos que tengo 2 métodos:

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

def method2(self): 
    ... 

Si no quiero hacer ningún cambio para metodo1, la forma de obtener el nombre de la persona que llama (en este ejemplo, el nombre es method1) en metodo2 ?

+2

Sí. Ahora solo quiero generar algo de documentación y solo para pruebas. – zsong

+0

La tecnología es una cosa, la metodología es otra. – zsong

+3

posible duplicado de [Obtener el nombre de la función del que llama dentro de otra función en Python?] (Http://stackoverflow.com/questions/900392/getting-the-caller-function-name-inside-another-function-in-python) – ChrisF

Respuesta

152

inspect.getframeinfo y otras funciones relacionadas en inspect pueden ayudar:

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

esta introspección está destinada a ayudar a la depuración y el desarrollo; no es recomendable confiar en él con fines de funcionalidad de producción. Versión

+11

"no es aconsejable confiar en él para fines de funcionalidad de producción". Por qué no? – beltsonata

+11

@beltsonata depende de la implementación de CPython, por lo que el código que use esto se romperá si alguna vez intentas usar PyPy o Jython u otros tiempos de ejecución. eso está bien si solo está desarrollando y depurando localmente pero no realmente algo que desee en su sistema de producción. – robru

+2

¡Hola chicos! Después de todo. ¿Todavía no está listo para producción? –

69

Shorter:

import inspect 

def f1(): f2() 

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

f1() 

(con gracias a @Alex, y Stefaan Lippen)

+0

Hola, estoy obteniendo el siguiente error cuando ejecuto esto: Archivo "/usr/lib/python2.7/inspect.py ", línea 528, en sourcesource si no es archivo de origen y archivo [0] + archivo [-1]! = '<>': IndexError: índice de cadena fuera de rango ¿Puede dar su sugerencia? Gracias de antemano – Pooja

+0

Esto enfoque me dio un error: KeyError: '__main__' – Praxiteles

22

Yo he llegado con una versión ligeramente más largo que trata de construir un nombre de método completo que incluye módulo y clase .

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

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

Impresionante, esto funcionó bien para mí en mi código de registro, donde puedo llamar desde muchos lugares diferentes. Muchas gracias. –

+0

A menos que elimine también 'stack', sigue filtrando marcos debido a referencias circulares como se explica en [inspect-docs] (https://docs.python.org/3.6/library/inspect.html#the-interpreter-stack) – ankostis

+0

@ankostis ¿tiene algún código de prueba? para demostrar que? –

25

Esto parece funcionar bien:

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

poco de una amalgama de las cosas anteriormente. Pero aquí está mi oportunidad.

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 

Uso:

@print_caller_name(4) 
def foo(): 
    return 'foobar' 

def bar(): 
    return foo() 

def baz(): 
    return bar() 

def fizz(): 
    return baz() 

fizz() 

salida es

level :    module    : name 
-------------------------------------------------- 
    3 :    None    : fizz 
    2 :    None    : baz 
    1 :    None    : bar 
    0 :   __main__   : foo 
+0

Esto generará un error de índice si la profundidad de la pila solicitada es mayor que la real. Use 'modules = [(index, inspect.getmodule (stack [index] [0])) para el índice invertido (range (1, min (stack_size, len (inspect.stack()))))]' para obtener el módulos. – jake77

1

he encontrado una manera si usted va a través de clases y quiero la clase el método pertenece y el método. Se necesita un poco de trabajo de extracción, pero tiene su punto. Esto funciona en 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() 
Cuestiones relacionadas