[Python-ideas] Briefer string format

Eric V. Smith eric at trueblade.com
Tue Jul 21 07:43:12 CEST 2015


On 7/21/2015 1:16 AM, Stephen J. Turnbull wrote:
> Eric V. Smith writes:
> 
>  > instead of trying to figure out that the numeric-looking '0' gets
>  > converted to an integer, and the non-numeric-looking 'c' gets left as a
>  > string. That logic already exists in str.format(), so let's just
>  > leverage it from there.
> 
> Yes, please!  Guido's point that he wants no explicit use of locals(),
> etc, in the implementation took me a bit of thought to understand, but
> then I realized that it means a "macro" transformation with the
> resulting expression evaluated in the same environment as an explicit
> .format() would be.  And that indeed makes the whole thing as explicit
> as invoking str.format would be.

Right. That is indeed the beauty of the thing. I now think locals(),
etc. is a non-starter.

> I don't *really* care what transformations are used to get that
> result, but DRYing this out and letting the __format__ method of the
> indexed object figure out the meaning of the format string makes me
> feel better about my ability to *think* about the meaning of an f"..." 
> string.
> 
> In particular, isn't it possible that a user class's __format__ might
> decide that *all* keys are strings?  I don't see how the
> transformation Steve Dower proposed can possibly deal with that
> ambiguity.

In today's world:
'{a[0]:4d}'.format(a=a)
the object who's __format__() method is being called is a[0], not a. So
it's not up to the object to decide what the keys mean. That decision is
being made by the ''.format() implementation. And that's also the way
I'm envisioning it with f-strings.

> Another conundrum is that it's not obvious whether f"{a[01]}" is a
> SyntaxError (as it is with str.format) or equivalent to
> "{}".format(a['01']) (as my hypothetical user's class would expect).

It would still be a syntax error, in my imagined implementation, because
it's really calling ''.format() to do the expansion.

So here's what I'm thinking f'some-string' would expand to. As you note
above, it's happening in the caller's context:

new_fmt = remove_all_object_names_from_string(s)
objs = find_all_objects_referenced_in_string(s)
result = new_fmt.format(*objs)

So given:
X = namedtuple('X', 'name width')
a = X('Eric', 10)
value = 'some value'

then:
f'{a.name:*^{a.width}}:{value}'

would become this transformed code:
'{.name:*^{.width}}:{}'.format(*[a, a, value])
which would evaluate to:
'***Eric***:some value'

The transformation of the f-string to new_fmt and the computation of
objs is the only new part. The transformed code above works today.

Eric.


More information about the Python-ideas mailing list