<div dir="ltr">There are several mechanisms in the logging module to handle this use-case.<br>First, note that logging functions can take multiple arguments (<a href="https://docs.python.org/3/library/logging.html?highlight=logging#logging.Logger.debug">https://docs.python.org/3/library/logging.html?highlight=logging#logging.Logger.debug</a>):<br><br><font face="monospace, monospace">>>> import logging<br>>>> msg = "hello, %s! %s to %s you!"<br>>>> args = ("world", "pleased", "meet")<br>>>> logging.warning(msg, *args)</font><div><font face="monospace, monospace">WARNING:root:hello, world! pleased to meet you!</font><br><br>None of the string formatting will take place if the log call is below the level of the logger. It might be worth while to add a class that stores an unevaluated function, then evaluates the function when __str__ or __repr__ is called:<br><br><font face="monospace, monospace">>>> class MessageFunction:</font></div><div><font face="monospace, monospace">...     def __init__(self, func, *args, **kwargs):</font></div><div><font face="monospace, monospace">...         self.func = func</font></div><div><font face="monospace, monospace">...         self.args = args</font></div><div><font face="monospace, monospace">...         self.kwags = kwargs<br>...     def __str__(self):<br>...         return str(self.func(*self.args, **self.kwargs))<br>...     def __repr__(self):</font></div><div><font face="monospace, monospace">...         return repr(self.func(*self.args, **self.kwargs))<br><br>>>> import logging<br>>>> logging.debug("result = %s", MessageFunction(expensive_func, *args, **kwargs))</font></div><div><br>You can also add Filters to your logger: <a href="https://docs.python.org/3/library/logging.html?highlight=logging#logging.Filter">https://docs.python.org/3/library/logging.html?highlight=logging#logging.Filter</a><br><br></div></div><div class="gmail_extra"><br><div class="gmail_quote">On Tue, Feb 14, 2017 at 11:51 AM, MRAB <span dir="ltr"><<a href="mailto:python@mrabarnett.plus.com" target="_blank">python@mrabarnett.plus.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div class="HOEnZb"><div class="h5">On 2017-02-14 15:51, Barry Scott wrote:<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
A common pattern I use is to have logging calls for debug and information with my applications.<br>
The logging calls can be separately enabled and disabled.<br>
<br>
For example:<br>
<br>
debug_log_enabled = False<br>
def debugLog( msg ):<br>
      If debug_log_enabled:<br>
            print( ‘Debug: %s’ % (msg,) )<br>
<br>
Then the caller can simple write:<br>
<br>
def main():<br>
      debugLog( ‘Start of main’ )<br>
<br>
This is fine until the evaluation of the msg becomes expensive.<br>
<br>
        debugLog( ‘info is %r’ % (expensiveFunction(),) )<br>
<br>
What would be nice is to be able to avoid evaluation the tuple of arguments if debug is<br>
disabled as this can be expensive. I can write this:<br>
<br>
        if debug_log_enabled:  debugLog( ‘info is %r’ % (expensiveFunction(),) )<br>
<br>
But that is a more code then I would like to write. And if the debug code is a performance problem cannot<br>
be left in the production code.<br>
<br>
I could combine the boolean and the log function by using a class to tidy up the implementation.<br>
<br>
class DebugLog:<br>
        def __init__( self, enabled = False ):<br>
                self.enabled = enabled<br>
<br>
        def __bool__( self ):<br>
                return self.enabled<br>
<br>
        def __call__( self, msg ):<br>
                if self.enabled: print( ‘Debug: %s’ % (msg,) )<br>
<br>
And call like this:<br>
<br>
        dbg_log = DebugLog()<br>
<br>
       If dbg_log: dbg_log( ‘a debug message’ )<br>
<br>
But I’d like to only write:<br>
<br>
        dbg_log( ‘a debug message’ )<br>
<br>
And have the evaluation of the argument skipped unless its dbg_log is enabled.<br>
<br>
I cannot see how to do this with python as it stands.<br>
<br>
Something would have to be added to allow python to short circuit the argument tuple evaluation.<br>
<br>
Maybe python can check for a special dunder on the class that know how to do this idiom, __if_true_call__?<br>
<br>
Thoughts?<br>
<br>
</blockquote></div></div>
You could let your debugging function accept a callable and use lambda to delay execution:<br>
<br>
def debugLog(msg):<br>
    if debug_log_enabled:<br>
        if callable(msg):<br>
            msg = msg()<br>
<br>
        print('Debug: %s' % (msg, ))<span class=""><br>
<br>
<br>
debugLog('Start of main')<br>
<br></span>
debugLog(lambda: 'info is %r' % (expensiveFunction(), ))<div class="HOEnZb"><div class="h5"><br>
<br>
______________________________<wbr>_________________<br>
Python-ideas mailing list<br>
<a href="mailto:Python-ideas@python.org" target="_blank">Python-ideas@python.org</a><br>
<a href="https://mail.python.org/mailman/listinfo/python-ideas" rel="noreferrer" target="_blank">https://mail.python.org/mailma<wbr>n/listinfo/python-ideas</a><br>
Code of Conduct: <a href="http://python.org/psf/codeofconduct/" rel="noreferrer" target="_blank">http://python.org/psf/codeofco<wbr>nduct/</a></div></div></blockquote></div><br></div>