
On 8/9/2015 9:02 PM, Eric V. Smith wrote:
On 8/9/2015 8:24 PM, Peter Ludemann wrote:
What if logging understood lambda? (By testing for types.FunctionType). This is outside PEP 498, but there might be some recommendations on how "lazy" evaluation should be done and understood by some functions.
e.g.: log.info <http://log.info>(lambda: f'{foo} just did a {bar} thing')
It's not pretty, but it's not too verbose. As far as I can tell, PEP 498 would work with this because it implicitly supports closures — that is, it's defined as equivalent to log.info <http://log.info>(lambda: ''.join([foo.__format__(), ' just did a ', bar.__format__(), ' thing']))
That basically works: class Foo: def __init__(self, name): self.name = name
def __format__(self, fmt): print(f'__format__: {self.name}') return f'{self.name}'
class Logger: # accumulate log messages until flush is called def __init__(self): self.values = []
def log(self, value): self.values.append(value)
def flush(self): for value in self.values: if callable(value): value = value() print(f'log: {value}')
logger = Logger()
f1 = Foo('one') f2 = Foo('two') print('before log calls') logger.log('first log message') logger.log(lambda:f'f: {f1} {f2}') logger.log('last log message') print('after log calls') f1 = Foo('three') logger.flush()
produces:
before log calls after log calls log: first log message __format__: three __format__: two log: f: three two log: last log message
But note that when the lambdas are called, f1 is bound to Foo('three'), so that's what's printed. I don't think that's what the logging module would normally do, since it wouldn't see the rebinding.
I guess you'd have to change logging to do something special if it had a single argument which is a callable, or add new interface to it.
And of course you'd have to live with the ugliness of lambdas in the logging calls.
So, I can't say I'm a huge fan of the approach. But writing examples using f-strings is way more fun that using %-formatting or str.format!
Here's a better example that shows the closure. Same output as above: class Foo: def __init__(self, name): self.name = name def __format__(self, fmt): print(f'__format__: {self.name}') return f'{self.name}' class Logger: # accumulate log messages until flush is called def __init__(self): self.values = [] def log(self, value): self.values.append(value) def flush(self): for value in self.values: if callable(value): value = value() print(f'log: {value}') def do_something(logger): f1 = Foo('one') f2 = Foo('two') print('before log calls') logger.log('first log message') logger.log(lambda:f'f: {f1} {f2}') logger.log('last log message') print('after log calls') f1 = Foo('three') logger = Logger() do_something(logger) logger.flush()