[Python-ideas] Standard way to get caller name and easy call stack access

anatoly techtonik techtonik at gmail.com
Thu Mar 22 08:29:05 CET 2012


On Thu, Mar 22, 2012 at 3:17 AM, Sven Marnach <sven at marnach.net> wrote:
> anatoly techtonik schrieb am Do, 22. Mär 2012, um 00:03:47 +0300:
>> Seems like the only way to get caller name in Python is to use inspect
>> module [1]
>> It seems that this way is not recommended (I wonder why?) and there is no other.
>
> Using introspection in production code is not recommended in general,
> with some exceptions, since the main purpose of introspection is
> debugging.  *If* you want to do this at all, the recommended way is to
> use the inspect module.  (And there is another way -- at least in
> CPython you can use 'sys._getframe().f_back.f_code.co_name'.)

If sys._getframe() is not available in Jython, IronPython and PyPy
then I won't use that for debug mode output in libraries.

The mechanism with `inspect` is complicated, incomplete - seems like
it was not designed with object oriented concepts in mind. Look at the
comments in the gist I posted before - after several iterations I
still don't know how to distinguish between function name and static
method call. I suspect there is no such info at all, because the API
level of `inspect` objects is too low level. Other proof for that is
that gist is impossible to understand without thoroughly reading the
documentation.

The inspect module was added around the time new style object
appeared, and debugging was concentrated around the byte code
compilation. Nobody thought about big applications where all these
frames, line numbers, stack space and indexes of last attempted
instruction in bytecode don't make any sense.

Writing helpers for debugging call stacks could be easy.

>> The stackoverflow question about how to get callers method namd [1]
>> got 3k views over 1 year, so the recipe seems to be useful. I've
>> developed a similar snippet [2] that also extracts a module and class
>> name in addition to method. To me this snippet is very handy to insert
>> in print statements to see who uses a certain function at run-time.
>>
>> The output from this function is:
>>   spyderlib.widgets.externalshell.introspection.NotificationThread.run
>
> The missing link here seems to be that code objects don't allow access
> to PEP 3155 qualified names -- if they did, this would be rather easy
> to do.  How about adding a `co_qualname` attribute to code objects?
> It could point to the same string the function object points to, so
> the overhead would be minimal.

Thanks for PEP 3155. I read it, but completely forgot the word
"qualified". Despite the discussion inside that "full name" is a bad
choice - this is the first thing that comes to mind at the prompt of
search engine.

Adding co_qualname is an easy low-level solution, but looking back I
don't want anybody to went through the path of getting through all the
gory details about python frames, filtering all the confusing and
irrelevant pieces just to get to call stack. So, the argument - that
this part of Python should be simplified, because beautiful is better
than ugly. More arguments at the end of the letter.

There is also technical argument against using existing technique of
frame access, which is explained in a big note here
http://docs.python.org/library/inspect.html#the-interpreter-stack

>> So, I'd propose to include caller_name() function somewhere and name
>> it somehow.
>
> I don't think this would be necessary if the qualified name could be
> accessed from the frame object in some way.
>
>> But there is more to that. Maybe too late for Python 3,
>> but still an idea - make call stack a normal Python feature
>
> Not sure what you are talking about here.

For example you need to explain a Python beginner what a Stackless is.
If you have an abstraction, you just do:

>>> for i,e in enumerate( call_stack() ):
...        print " "*i, e
...
__main__
  module.something
     module2.we_are_here

Not an abstraction - people can actually play with it, and then you
say - "This is how CPython works. In Stackless there is no call stack
- there is a queue":

__main__
module.something
-------------------------------- ^^^ we were here
module2.we_are_here
module.something
__main__


So, the ability to operate the "call stack" concept is that I call the
language feature. If people can see it, touch it and play with it -
you can expect to see a lot of cool things appear about it. I could
talk about perspectives of exploratory/incremental programming, and
run-time rollbacks, but I better stop right here.
--
anatoly t.



More information about the Python-ideas mailing list