2

In the test script below based on previous answers, all techniques provide the desired result of returning an informative message to the screen and a logging file.

Besides execution time which seems to be much slower for the inspect methods, I can't see any way to choose between these alternatives. Are there any hidden pitfalls in one or the other techniques? I'll be moving the project Python 3 in the future so something most forward-compatible would be better than something which is fastest now.

Results:

I am Bob, an instance of B, speaking from f1
I am Bob, an instance of B, speaking from f2
I am Bob, an instance of B, speaking from f3
I am Bob, an instance of B, speaking from f4
I am Bob, an instance of B, speaking from g
I am Bob, an instance of B, speaking from h

Script:

class A(object):
    def __init__(self):
        self.cname = self.__class__.__name__
        logfmt     = "%(levelname)s - %(message)s"
        logging.basicConfig(filename="logme.log", level=logging.DEBUG, 
                            format=logfmt, filemode='w')
        self.logger = logging.getLogger()

class B(A):
    def __init__(self, name):
        self.name = name
        A.__init__(self)

    def whoami(self):
        return inspect.stack()[1][3]

    def whosdaddy(self):
        return inspect.stack()[2][3]

    def who_i(self, i=None):
        if i==None: i=1
        return inspect.stack()[i][3]

    def mee(self):
        return inspect.stack()[1][3]

    def f1(self):
        msg   = ('I am {}, an instance of {}, speaking from {}'.format(self.name, self.cname, self.mee()))
        print msg
        self.logger.info(msg) 

    def f2(self):    # 2011 https://stackoverflow.com/a/5067654/3904031
        me  = inspect.stack()[0][3]
        msg   = ('I am {}, an instance of {}, speaking from {}'.format(self.name, self.cname, me))
        print msg
        self.logger.info(msg) 

    def f3(self):    # 2015 https://stackoverflow.com/a/33159791/3904031
        msg   = ('I am {}, an instance of {}, speaking from {}'.format(self.name, self.cname, self.whoami()))
        print msg
        self.logger.info(msg) 

    def f4(self):
        msg   = ('I am {}, an instance of {}, speaking from {}'.format(self.name, self.cname, self.who_i(1)))
        print msg
        self.logger.info(msg) 

    def g(self):
        me  = sys._getframe().f_code.co_name    # 2013 https://stackoverflow.com/a/15725912/3904031
        msg   = ('I am {}, an instance of {}, speaking from {}'.format(self.name, self.cname, me))
        print msg
        self.logger.info(msg) 

    def h(self):
        frame = inspect.currentframe()
        me    = inspect.getframeinfo(frame).function    # 2015 https://stackoverflow.com/a/33162432/3904031
        msg   = ('I am {}, an instance of {}, speaking from {}'.format(self.name, self.cname, me))
        print msg
        self.logger.info(msg) 

import sys, inspect, logging

b = B('Bob')

for x in ['f1', 'f2', 'f3', 'f4', 'g', 'h']:
    getattr(b, x)()

1 Answer 1

1

This turns out to be an x/y problem. logging seems to have all of the functionality that I need, per this answer.

By using the attribute %(funcName)s in the format statement, the following script does everything without any need to look into the stack, including the echo to the console.

Documentation: https://docs.python.org/3/library/logging.html#logrecord-attributes

I am Bob, an instance of B, speaking from  i

from:

class A(object):
    def __init__(self):

        self.cname = self.__class__.__name__

        logformat  = '%(message)s %(funcName)s '

        logging.basicConfig(filename="logme.log", level=logging.DEBUG, 
                            format=logformat, filemode='w')

        self.logger = logging.getLogger()

        console   = logging.StreamHandler()   # no more print statements, yay!
        formatter = logging.Formatter(logformat)
        console.setFormatter(formatter)

        console.setLevel(logging.DEBUG)

        logging.getLogger('').addHandler(console)

class B(A):
    def __init__(self, name):
        self.name = name
        A.__init__(self)

    def i(self):
        msg   = ('I am {x.name}, an instance of {x.cname}, speaking from '.format(x=self))
        self.logger.info(msg)

import sys, inspect, logging

b = B('Bob')

b.i()
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.