[Python-Dev] PEP-498: Literal String Formatting
Eric V. Smith
eric at trueblade.com
Mon Aug 10 03:05:45 CEST 2015
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()
More information about the Python-Dev
mailing list