metaprogramming - Name of a Python function in a stack trace -
in both python2 , python3, in stack trace __name__
of function not used, original name (the 1 specified after def
) used instead.
consider example:
import traceback def a(): return b() def b(): return c() def c(): print("\n".join(line.strip() line in traceback.format_stack())) a.__name__ = 'a' b.__name__ = 'b' c.__name__ = 'c' a();
the output is:
file "test.py", line 16, in <module> a(); file "test.py", line 4, in return b() file "test.py", line 7, in b return c() file "test.py", line 10, in c print("\n".join(line.strip() line in traceback.format_stack()))
why so? how change name used in stack trace? __name__
attribute used then?
so, every function has 3 things can considered being name of function:
the original name of code block
it's stored in f.__code__.co_name
(where f
function object). if use def orig_name
create function, orig_name
name. lambas it's <lambda>
.
this attribute readonly , can't changed. way create function custom name in runtime i'm aware of exec
:
exec("""def {name}(): print '{name}' """.format(name='any')) in globals() any() # prints 'any'
(there more low-level way this mentioned in comment question.)
the immutability of co_name
makes sense: can sure name see in debugger (or stack trace) same see in source code (along filename , line number).
the __name__
attribute of function object
it's aliased func_name
.
you can modify (orig_name.__name__ = 'updated name'
) , surely on daily basis: @functools.wraps
copies __name__
of decorated function new one.
__name__
used tools pydoc
, that's why need @functools.wraps
: don't see technical details of every decorator in documentation. @ example:
from functools import wraps def decorator1(f): def decorated(*args, **kwargs): print 'start1' f(*args, **kwargs) return decorated def decorator2(f): @wraps(f) def decorated(*args, **kwargs): print 'start2' f(*args, **kwargs) return decorated @decorator1 def test1(): print 'test1' @decorator2 def test2(): print 'test2'
here pydoc
output:
functions decorator1(f) decorator2(f) test1 = decorated(*args, **kwargs) test2(*args, **kwargs)
with wraps
there no sign of decorated
in documentation.
name of reference
one more thing can called function name (though hardly is) name of variable or attribute reference function stored.
if create function def name
, name
attribute added current scope. in case of lambda
should assign result variable: name = lambda: none
.
obviously can create more 1 reference same function , references can have different names.
the way 3 things connected each other def foo
statement creates function object both __name__
, __code__.co_name
equal foo
, assign foo
attribute of current scope. not bound in way , can different each other:
import traceback def make_function(): def orig_name(): """docstring here """ traceback.print_stack() return orig_name globals()['name_in_module'] = make_function() name_in_module.__name__ = 'updated name' name_in_module()
output:
file "my.py", line 13, in <module> name_in_module() file "my.py", line 7, in orig_name traceback.print_stack()
pydoc:
functions make_function() name_in_module = updated name() docstring here
i thank other people comments , answers, helped me organize thoughts , knowledge.
Comments
Post a Comment