code python function introspection traceback

code - inspect python 3



Determine el nombre de la función desde dentro de esa función(sin usar el rastreo) (18)

En Python, sin usar el módulo de traceback , ¿hay una manera de determinar el nombre de una función desde dentro de esa función?

Digamos que tengo un módulo foo con una barra de funciones. Al ejecutar foo.bar() , ¿hay una forma para que bar sepa el nombre de la barra? O mejor aún, ¿el nombre de foo.bar ?

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


Aquí hay un enfoque a prueba de futuro.

Combinar las sugerencias de @ CamHart y @ Yuval con la respuesta aceptada de @ RoshOxymoron tiene el beneficio de evitar:

  • _hidden métodos _hidden y potencialmente obsoletos
  • indexación en la pila (que podría reordenarse en futuras pitones)

Así que creo que esto funciona bien con las futuras versiones de Python (probadas en 2.7.3 y 3.3.2):

from __future__ import print_function import inspect def bar(): print("my name is ''{}''".format(inspect.currentframe().f_code.co_name))


Encontré una envoltura que escribirá el nombre de la función

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

Esto imprimirá

my_funky_name

TALÓN


Esto se deriva realmente de las otras respuestas a la pregunta.

Aquí está mi opinión:

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

La posible ventaja de esta versión sobre el uso de inspect.stack () es que debería ser miles de veces más rápida [consulte la publicación de Alex Melihoff y los horarios con respecto al uso de sys._getframe () en lugar de usar inspect.stack ()].


Hago mi propio enfoque utilizado para llamar súper con seguridad dentro de un escenario de herencia múltiple (pongo todo el código)

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

uso de la muestra:

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

probandolo

a = C() a.test()

salida:

called from C called from A called from B

Dentro de cada método @with_name decorado, tiene acceso a self .__ fname__ como el nombre de la función actual.


Hay algunas maneras de obtener el mismo resultado:

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)

Tenga en cuenta que las llamadas a inspect.stack son miles de veces más lentas que las alternativas:

$ 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


Hice lo que dijo CamHart:

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

Salida:

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

Proceso terminado con el código de salida 0


Mantengo esta práctica utilidad cerca:

import inspect myself = lambda: inspect.stack()[1][3]

Uso:

myself()


Puede obtener el nombre con el que se definió utilizando share , pero puede que no sea el nombre con el que se llamó a la función:

import inspect def Foo(): print inspect.stack()[0][3] Foo2 = Foo >>> Foo() Foo >>> Foo2() Foo

Si esa distinción es importante para ti o no, no puedo decirlo.


Puedes usar un decorador:

def my_function(name=None): return name def get_function_name(function): return function(name=function.__name__) >>> get_function_name(my_function) ''my_function''


Python no tiene una función para acceder a la función o su nombre dentro de la misma función. Se ha proposed pero rechazado. Si no quieres jugar con la pila, debes usar "bar" o bar.__name__ dependiendo del contexto.

El aviso de rechazo dado es:

Este PEP es rechazado. No está claro cómo se debe implementar o cuál debe ser la semántica precisa en casos extremos, y no se dan suficientes casos de uso importantes. La respuesta ha sido tibia en el mejor de los casos.


Recientemente traté de usar las respuestas anteriores para acceder a la cadena de documentación de una función desde el contexto de esa función, pero como las preguntas anteriores solo devolvían la cadena de nombre, no funcionó.

Afortunadamente encontré una solución simple. Si, como yo, desea referirse a la función en lugar de simplemente obtener la cadena que representa el nombre, puede aplicar eval () a la cadena del nombre de la función.

import sys def foo(): """foo docstring""" print(eval(sys._getframe().f_code.co_name).__doc__)


Supongo que inspect es la mejor manera de hacer esto. Por ejemplo:

import inspect def bar(): print("My name is", inspect.stack()[0][3])


Usa esto (basado en la respuesta de #Ron Davis):

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


print(inspect.stack()[0].function) también funciona (Python 3.5).


functionNameAsString = sys._getframe().f_code.co_name

Quería algo muy similar porque quería poner el nombre de la función en una cadena de registro que iba en varios lugares de mi código. Probablemente no sea la mejor manera de hacerlo, pero aquí hay una forma de obtener el nombre de la función actual.


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


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

En IDE las salidas de código

hola soy foo papi es

hola soy bar papi es foo

hola soy bar papi es


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

Prueba:

a = A() a.test_class_func_name() test_func_name()

Salida:

test_class_func_name test_func_name