
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.