9

Is there a way so that the following code:

import traceback

def log(message):
    print "%s: %s" %(traceback.extract_stack()[0:-1][-1][2], message)

def f1():
    log("hello")

class cls(object):
    def f1(self):
        log("hi there")

f1()
mycls = cls()
mycls.f1()

displays:

f1: hello
cls.f1: hi there

instead of:

f1: hello
f1: hi there

?

I tried to use module 'inspect' but was not successful...

Julien

EDIT:

The point here is for 'log' function to be able to retrieve its caller name on its own (using traceback, inspect, or any mean necessary).

I do not want to pass the class name, or anything else than 'message' to the 'log' function.

Julien REINAULD
  • 499
  • 4
  • 13
  • 3
    Can you use [`__qualname__`](https://www.python.org/dev/peps/pep-3155/)? – mgilson Aug 02 '17 at 20:27
  • https://stackoverflow.com/questions/10973362/python-logging-function-name-file-name-line-number-using-a-single-file – Eugene Sh. Aug 02 '17 at 20:30
  • @mgilson given the python2.x syntax in the question I'd guess not? – Anthony Sottile Aug 02 '17 at 20:30
  • @AnthonySottile -- Yeah, I was just coming to that conclusion myself -- though there is an (imperfect) substitute on pypi (https://pypi.python.org/pypi/qualname/) – mgilson Aug 02 '17 at 20:33
  • @AnthonySottile -- Also, from `frame` objects, I don't think you actually have a reference back to the function object -- Only it's name. – mgilson Aug 02 '17 at 20:41
  • @mgilson indeed, there's `f_code` but that's only the code object (a function object contains code + some other things) – Anthony Sottile Aug 02 '17 at 20:44
  • @mgilson holy hell: "This module uses source code inspection to figure out how (nested) classes and functions are defined in order to determine the qualified names for them. That means parsing the source file, and traversing the AST (abstract syntax tree). This sounds very hacky, and it is, but the Python interpreter itself does not have the necessary information, so this justifies extreme measures." – juanpa.arrivillaga Aug 02 '17 at 20:51
  • @everyone: yes, as of today, I use python 2.7.12 (default python on Ubuntu 16.04.2). Would python3 allow me to do what I need? – Julien REINAULD Aug 03 '17 at 09:46
  • @JulienREINAULD: In your question "displays" and "instead of" are swapped, isn't it? – Laurent LAPORTE Aug 25 '17 at 15:04
  • @LaurentLAPORTE Hum I don't think so. I wish the full name instead of the leaf name – Julien REINAULD Aug 29 '17 at 15:09

2 Answers2

2

So I finally came up this method:

#!/usr/bin/env python3

def log(message):
    import inspect
    import gc
    code = inspect.currentframe().f_back.f_code
    func = [obj for  obj in  gc.get_referrers(code) if inspect.isfunction(obj)][0]
    print(func.__qualname__, message)

It needs python3 so that __qualname__ can be used.

Julien REINAULD
  • 499
  • 4
  • 13
-1

The inspect module is very powerful, and can be used in a similar fashion to the way you use traceback to get the name of the function, and probably also the class name. But you can simply make use of the fact that you have the self instance variable, which knows of its own type/class:

import inspect

class cls(object):
    def f1(self):
        this_class_name = type(self).__name__
        this_func_name = inspect.currentframe().f_code.co_name
        print(this_class_name, this_func_name)

mycls = cls()
mycls.f1()
jmd_dk
  • 8,399
  • 4
  • 48
  • 72
  • You are correct. However, what I am really trying to achieve (sorry I did not asked that explicitely in my question) is to retrieve the class name from traceback, without the need to pass it as an argument to my 'log' function. – Julien REINAULD Aug 03 '17 at 09:39