[Python-ideas] Briefer string format

Steve Dower Steve.Dower at microsoft.com
Mon Jul 20 20:41:14 CEST 2015


Eric V. Smith wrote:
> On 07/20/2015 01:25 PM, Guido van Rossum wrote:
>> Perhaps surprisingly, I find myself leaning in favor of the
>> f'...{var}...' form. It is explicit in the variable name.
>>
>> Historically, the `x` notation as an alias for repr(x) was meant to
>> play this role -- you'd write '...' + `var` + '...', but it wasn't
>> brief enough, and the `` are hard to see. f'...' is more explicit, and
>> can be combined with r'...' and b'...' (or both) as needed.
> 
> We didn't implement b''.format(), for a variety of reasons. Mostly to do with
> user-defined types returning unicode from __format__, if I recall correctly.
> 
> So the idea is that
> f'x:{a.x} y:{y}'
> would translate to bytecode that does:
> 'x:{a.x} y:{y}'.format(a=a, y=y)
> 
> Correct?

That's exactly what I had in mind, at least. Indexing is supported in format strings too, so f'{a[1]}' also becomes '{a[1]}'.format(a=a), but I don't think there are any other strange cases here. I would vote for f'{}' or f'{0}' to just be a SyntaxError.

I briefly looked into how this would be implemented and while it's not quite trivial/localized, it should be relatively straightforward if we don't allow implicit merging of f'' strings. If we wanted to allow implicit merging then we'd need to touch more code, but I don't see any benefit from allowing it at all, let alone enough to justify seriously messing with this part of the parser.

> I think I could leverage _string.formatter_parser() to do this, although it's
> been a while since I wrote that. And I'm not sure what's available at compile
> time. But I can look into it.
> 
> I guess the other option is to have it generate:
> 'x:{a.x} y:{y}'.format_map(collections.ChainMap(globals(), locals(),
> __builtins__))
> 
> That way, I wouldn't have to parse the string to pick out what variables are
> referenced in it, then have .format() parse it again.

If you really want to go with the second approach, ChainMap isn't going to be sufficient, for example:

>>> def f():
...   x = 123
...   return ['{x}'.format_map(collections.ChainMap(globals(), locals(), __builtins__)) for _ in range(1)]
...
>>> f()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 3, in f
  File "<stdin>", line 3, in <listcomp>
KeyError: 'x'

If the change also came with a dict-like object that will properly resolve variables from the current scope, that would be fine, but I don't think it can be constructed in terms of existing names. (Also bear in mind that other Python implementations do not necessarily provide sys._getframe(), so defining the lookup in terms of that would not be helpful either.)

Cheers,
Steve

> Eric.



More information about the Python-ideas mailing list