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