This came up 2 years ago. You might want to read this article on LWN that covered the discussion.
https://lwn.net/Articles/716986/ <https://lwn.net/Articles/716986/> Assuming that the log code you call will spot a callable and call it you can do this: log_function( lambda : expensive_function() ) Otherwise you end up needed to do: if log_obj.is_enabled(): log_obj.log_function( expensive_function() ) If log is an object that provides __bool__ and __call__ you could write: if log_obj: log_obj( expensive_function() ) or log_obj and log_obj( expensive_functon() ) For example: class Log: def __init__( self ): self.enabled = True def __bool__( self ): return self.enabled def __call__( self, msg ): print( 'Log: %s' % (msg,) ) log = Log() print( 'Log when enabled' ) if log: log( 'log is enabled' ) log and log( 'log is enabled' ) log.enabled = False print( 'Log when disabled' ) if log: log( 'log is enabled' ) log and log( 'log is enabled' ) print( 'Done' ) Which produces: $ python3 log.py Log when enabled Log: log is enabled Log: log is enabled Log when disabled Done Barry > On 15 May 2019, at 16:37, mak apuf <[email protected]> wrote: > > Hello all, > > Let's consider logging.debug(expensive_function()) > > There are a few possibilities to run an expensive function when > logging only if the log is effectively output : > > - eager formatting + calling by using fstrings or .format(expensive_func()) > - formatting being done lazily by separating the log string from the > arguments (by using % syntax which is dated maybe) > - creating a Lazy object that calls expensive_func when calling its > __str__ method, but that it a bit cumbersome because you have to > provide a lazy class for each, that only work for string values and > the cost of creating Lazy is eager. > - checking logging.isEnabledFor(lvl) explicitely (but then the level > is displayed twice, in enabled_for and in logging.LEVEL) > > Maybe we can integrate a form of lazy evaluation for simple logging. > Different options are : > a- just evaluate when an argument is callable (not bw compatible, what > if this is unexpected and has side effects) > b- provide a LazyFormatter that does the preceding for any "%s" or > "%d" arg when used > c- provide a callable as part of the logging arguments and provide a > "%*s or %*d" format string instead of %s and %d (by example) for > calling the function before embedding it > d- check if a parameter has a special method such as __lazy__ at render time > e- provide a Lazy class in logging module to wrap lazy logging idiom: > > class Lazy : > def __init__(self, callable, *args, **kwargs) : > self.callable = callable > self.args=args > self.kwargs=kwargs > > def __lazy__(self) : return self.callable(*args, **kwargs) > > and checking if an argument is of Lazy type (again the drawback is > that this eagerly instanciate this class) > > I'd prefer b,c or d+e > > any thoughts? > > > -- > makapuf > _______________________________________________ > Python-ideas mailing list > [email protected] > https://mail.python.org/mailman/listinfo/python-ideas > Code of Conduct: http://python.org/psf/codeofconduct/ >
_______________________________________________ Python-ideas mailing list [email protected] https://mail.python.org/mailman/listinfo/python-ideas Code of Conduct: http://python.org/psf/codeofconduct/
