Python function name in stack trace

In Python2 and Python3, the __name__ function trace is not used in the stack trace; instead, the original name (specified after def ) is used.

Consider an example:

 import traceback def a(): return b() def b(): return c() def c(): print("\n".join(line.strip() for line in traceback.format_stack())) a.__name__ = 'A' b.__name__ = 'B' c.__name__ = 'C' a(); 

Output:

 File "test.py", line 16, in <module> a(); File "test.py", line 4, in a return b() File "test.py", line 7, in b return c() File "test.py", line 10, in c print("\n".join(line.strip() for line in traceback.format_stack())) 

Why is that? How to change the name used in the stack trace? Where is the __name__ attribute used?

+8
python metaprogramming
source share
2 answers

Thus, basically every function has three things that can be considered function names:

Source code block name

It is stored in f.__code__.co_name (where f is the function object). If you create a function def orig_name , orig_name is the name. For lambas, this is <lambda> .

This attribute is read-only and cannot be changed. So the only way to create a function with a custom name at runtime that I know of is exec :

 exec("""def {name}(): print '{name}' """.format(name='any')) in globals() any() # prints 'any' 

(There is also a lower-level way to do this , as mentioned in the commentary on the question.)

The inevitability of co_name really makes sense: with this, you can be sure that the name that you see in the debugger (or just a stack trace) is exactly the same as what you see in the source code (along with the file name and the string number).

The __name__ attribute of a function object

It also has the alias func_name .

You can change it ( orig_name.__name__ = 'updated name' ), and you certainly do it daily: @functools.wraps copies __name__ of the decorated function to a new one.

__name__ used by tools like pydoc , so you need @functools.wraps : so you don't see the technical details of each decorator in your documentation. Take a look at an 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 is the pydoc output:

 FUNCTIONS decorator1(f) decorator2(f) test1 = decorated(*args, **kwargs) test2(*args, **kwargs) 

With wraps , there is no decorated sign in the documentation.

Link Name

Another thing that can be called the name of a function (although it is unlikely to exist) is the name of the variable or attribute that stores the link to this function.

If you create a function with def name , the name attribute will be added to the current scope. In the case of lambda you should assign the result to some variable: name = lambda: None .

Obviously, you can create multiple links to the same function, and all these links can have different names.


The only way to relate all three things to each other is with the def foo operator, which creates a function object with __name__ and __code__.co_name equal to foo and assigns the current volume to its foo attribute. But they are in no way connected and may differ from 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 for comments and answers, they helped me organize my thoughts and knowledge.

+7
source share

Tried to research the implementation of CPython , definitely not an expert. As pointed out in the comments, when the stack entry f is printed, the f.__code__.co_name attribute is used. In addition, f.__name__ initially set to f.__code__.co_name , but when you change the first, the latter does not change accordingly.

So I tried to change this directly, but this is not possible:

 >>> f.__code__.co_name = 'g' Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: readonly attribute >>> 

Why are there two ways to say the name of a function? Well, according to the documentation , __name__ is defined for "class, function, method, descriptor or instance of the generator", so in the case of functions that it maps to this attribute, for other objects it will map to something else.

+2
source share

All Articles