Outside the box string formatting idea

While the discussion of string formatting has focused on the concept of "format strings", it seems to me they are really format expressions. The expressions in this case are a bit like comprehensions in that they have special syntax/rules that is only valid in a small limited context. It may be possible to do that in this case as an actual expression rather than as a string and still get most of the benefits. Shorter more compressed isn't always better when it comes to readability. Consider this as a trial balloon. If there is clear consensus against it, no problem. It can be added to the rejected ideas section of PEP-498. Below are some examples to compare from the PEP-498. I strongly suggest posting the examples into idle or a syntax highlighting editor to really see what difference it makes in readability. (it won't run, but the highlighting will work.) I used % here, but that's just a place holder at this point, some other symbol could be used ... if this idea has any merit. Actually it could even be reduced to a parentheses with items separated by spaces. Examples from PEP: f'My name is {name}, my age next year is {age+1}, my anniversary is {anniversary:%A, %B %d, %Y}.' (% 'My name is ' name ', my age next year is ' (age+1) ', my anniversary is ' {anniversary ':%A, %B %d, %Y'} '.') # The {expres fmt_spec} sytnax is only valid in (% ...) expressions. f'He said his name is {name!r}.' (% 'He said his name is ' {name '!r'} '.') f'abc{expr1:spec1}{expr2!r:spec2}def{expr3:!s}ghi' (% 'abc' {expr1 'spec1'} {expr2 '!r:spec2'} 'def' expr3 'ghi') f'result={foo()}' (% 'result =' foo()) x = 10 y = 'hi' result = a' 'b' f'{x}' 'c' f'str<{y:^4}>' 'd' 'e' result = (% 'a' 'b' x 'c' '<' {y '^4'} '>' 'd' 'e') result = (% 'ab' x 'c<' {y '^4'} '>de')
f'{{k:v for k, v in [(1, 2), (3, 4)}}' '{k:v for k, v in [(1, 2), (3, 4)}'
(% {k:v for k, v in [(1, 2), (3, 4)}) This evaluates to a dictionary first. Most expressions naturally evaluate from the inside out, left to right. So there's no conflict. It just converts the dict comprehension to a string. The features allowed in (% ...) 1. Implicit concatenation is allowed for expressions separated by a space. But only in an explicit and limited context. 2. Expressions and format specs can be combined in braces separated by a space. Expressions without format specs don't need them. 3. It maintains the separation of strings and expressions. It does require typing more quotes than a f'...' format string, but the separation of items by only spaces along with syntax highlighting makes it much more readable I think. It's a run time expression, and not an object that can be bound to a name, just like f-strings. It's result can though, that is the same as f-strings. It removes the apparent controversy of evaluating strings. Which f-strings really don't do, because they are compiled to something very similar to what this does. It's just much more obvious with this suggestion that that isn't a problem. Complex expressions need ()'s around them in the format expression to ensure it's a single value, but the parser may be able to tell a + b, from a b. This is the explicit run time expression would do what a f-string does. Reduce repetition of names, allow text and expressions to be interspersed in the order they are used with as little extra noise as possible. The f-strings go one step further and eliminate the extra parentheses and quotes. But at the cost of having them run together and loosing the syntax highlighting of expressions in an editor. It also will make it harder for external syntax checkers to work. It probably would need some ironing out of some the edge cases though. A {expr} evaluates as a set. Just use expr, or {expr ''}. Things like that. I think this is as close to an f-string as we could get and still keep the expressions out of the strings. Cheers, Ron

On Sun, Aug 9, 2015 at 5:20 PM, Ron Adam <ron3200@gmail.com> wrote:
(% 'My name is ' name ', my age next year is ' (age+1)
This reminds me Javascript's automatic string promotion: $ node
name = 'Bob' 'Bob' age = 5 5 'My name is ' + name + ', my age next year is ' + (age+1) 'My name is Bob, my age next year is 6'
-1

On 08/09/2015 06:06 PM, Alexander Belopolsky wrote:
On Sun, Aug 9, 2015 at 5:20 PM, Ron Adam<ron3200@gmail.com> wrote:
(% 'My name is ' name ', my age next year is ' (age+1) This reminds me Javascript's automatic string promotion:
$ node
name = 'Bob' 'Bob' age = 5 5 'My name is ' + name + ', my age next year is ' + (age+1) 'My name is Bob, my age next year is 6'
It would only do that in a very narrow context. I'm not suggesting it be done outside of string format expressions. Cheers, Ron

My take: On 08/09/2015 02:20 PM, Ron Adam wrote:
It may be possible to do that in this case as an actual expression rather than as a string and still get most of the benefits. Shorter more compressed isn't always better when it comes to readability.
Really the idea here is brevity. The long-form versions are still available if they would be better in a particular instance.
(% 'result =' foo())
I found these interesting, reminds me of polish notation. However these would need enhancements to syntax as it would be currently invalid. f'' is likely easier to implement w/o syntax changes. Also, it doesn't look much like python. Cheers, -Mike

On 08/09/2015 06:14 PM, Mike Miller wrote:
My take:
On 08/09/2015 02:20 PM, Ron Adam wrote:
It may be possible to do that in this case as an actual expression rather than as a string and still get most of the benefits. Shorter more compressed isn't always better when it comes to readability.
Really the idea here is brevity. The long-form versions are still available if they would be better in a particular instance.
(% 'result =' foo())
I found these interesting, reminds me of polish notation. However these would need enhancements to syntax as it would be currently invalid. f'' is likely easier to implement w/o syntax changes. Also, it doesn't look much like python.
There are actually too parts... (% ...) Handles implicit concatination and string conversion. And {expr format} handles the formatting, inside (% ...) context only. So these only work in string format expressions, just like special syntax for comprehensions only works in comprehensions. As I suggested, I think it's the closest you can get and still not put the expressions into the strings. Comma's could be used to separate things, but it's not that much of a stretch to go from .... 'a' 'b' --> 'ab' to a = 'a' b = 'b' (% a b) --> 'ab' But we could have... (% a, b) If that seems more pythonic. Cheers, Ron

On 10/08/2015 00:08, Ron Adam wrote:
There are actually too parts...
(% ...) Handles implicit concatination and string conversion.
And {expr format} handles the formatting, inside (% ...) context only.
So these only work in string format expressions, just like special syntax for comprehensions only works in comprehensions.
As I suggested, I think it's the closest you can get and still not put the expressions into the strings.
Comma's could be used to separate things, but it's not that much of a stretch to go from ....
'a' 'b' --> 'ab'
to a = 'a' b = 'b' (% a b) --> 'ab'
But we could have...
(% a, b) If that seems more pythonic.
How does this gain over def f(*args): return ''.join(args) a='a' b='b' f(a, b) Rob Cliffe

On 08/09/2015 09:11 PM, Rob Cliffe wrote:
Comma's could be used to separate things, but it's not that much of a stretch to go from ....
'a' 'b' --> 'ab'
to a = 'a' b = 'b' (% a b) --> 'ab'
But we could have...
(% a, b) If that seems more pythonic.
How does this gain over
def f(*args): return ''.join(args) a='a' b='b' f(a, b)
To make that work in the same way you would also need to add a way to handle string conversion of expressions and formatting. The main gain is the removal of some of the syntax elements and repetive method or function calls that would be required in more complex situations. The point was to boil it down to the minimum that could be done and still not move the expression into the string. Lets look at this example... (% 'My name is ' name ', my age next year is ' (age+1) ', my anniversary is ' {anniversary ':%A, %B %d, %Y'} '.') Using functions and method calls it might become...
f = lambda *args: ''.join(args) _ = format import datetime name = 'Fred' age = 50 anniversary = datetime.date(1991, 10, 12)
f('My name is ', _(name), ', my age next year is ', _(age+1), ... ', my anniversary is ', _(anniversary, ':%A, %B %d, %Y'), '.')
'My name is Fred, my age next year is 51, my anniversary is :Saturday, October 12, 1991.' That isn't that much different and works today. A special format expression would remove some of the syntax elements and make it a standardised and cleaner looking solution. Because it requires the extra steps to define and rename the join and format functions to something shorter, it's not a standardised solution. Having it look the same in many programs is valuable. Also Nicks improvements of combining translation with it might be doable as well. Even with commas, it's still may be enough. Than again if everyone like the expressions in strings, it doesn't matter. Cheers, Ron

Ron Adam wrote:
How does this gain over
def f(*args): return ''.join(args) a='a' b='b' f(a, b)
To make that work in the same way you would also need to add a way to handle string conversion of expressions and formatting.
Lets look at this example...
(% 'My name is ' name ', my age next year is ' (age+1) ', my anniversary is ' {anniversary ':%A, %B %d, %Y'} '.')
Using functions and method calls it might become...
f = lambda *args: ''.join(args) _ = format import datetime name = 'Fred' age = 50 anniversary = datetime.date(1991, 10, 12)
f('My name is ', _(name), ', my age next year is ', _(age+1), ... ', my anniversary is ', _(anniversary, ':%A, %B %d, %Y'), '.')
'My name is Fred, my age next year is 51, my anniversary is :Saturday, October 12, 1991.'
That isn't that much different and works today. A special format expression would remove some of the syntax elements and make it a standardised and cleaner looking solution.
what about a slightly different "f"? def f(*args): f_args = [] for arg in args: if isinstance(arg, tuple): f_args.append(format(*arg)) else: f_args.append(format(arg)) return ''.join(f_args) import datetime name = 'Fred'; age = 50; anniversary = datetime.date(1991, 10, 12) print(f('My name is ', name, ', my age next year is ', age+1, ', my anniversary is ', (anniversary, ':%A, %B %d, %Y'), '.')) My name is Fred, my age next year is 51, my anniversary is :Saturday, October 12, 1991. -- By ZeD

On 08/10/2015 01:40 AM, Vito De Tullio wrote:
what about a slightly different "f"?
def f(*args): f_args = [] for arg in args: if isinstance(arg, tuple): f_args.append(format(*arg)) else: f_args.append(format(arg)) return ''.join(f_args)
import datetime name = 'Fred'; age = 50; anniversary = datetime.date(1991, 10, 12) print(f('My name is ', name, ', my age next year is ', age+1, ', my anniversary is ', (anniversary, ':%A, %B %d, %Y'), '.'))
My name is Fred, my age next year is 51, my anniversary is :Saturday, October 12, 1991.
What makes this difficult is it's a trinary operation combining three kinds of data. If it was a pure binary operation it would be simple. So the possible relationships are... 1. (string with format codes) + values # % and .format() 2. string + (formated values) 3. (string with values) + format codes 4. (string with both format codes and values) #f-strings 5. string + format codes + values # trinary operation? #2 is interesting. It can already be done by calling format(value, fmt). But maybe it can be improved on. If it had a dedicated operator, it might be nice enough to fill most needs. One of the main complaints with .format(...) is the length of the name, and it adds another level of parentheses. It can be split into separate fill and format operators and let precedence handle things to avoid conflicts with passing tuples. A quick hack... class S: def __init__(self, value): self.value = value def __lshift__(self, other): """Fill left most {}.""" return S(str(self.value).replace('{}', str(other), 1)) def __rfloordiv__(self, obj): """Format object with fmt string.""" return S(format(obj, self.value)) def __str__(self): return str(self.value) import datetime name = 'Fred' age = 50 anniversary = datetime.date(1991, 10, 12) print(S('My name is {}, my age next year is {}, my anniversary is {}.') << name << (age+1) << anniversary // S('%A, %B %d, %Y')) My name is Fred, my age next year is 51, my anniversary is Saturday, October 12, 1991. If those methods were added to strings, then it could look like this... print('My name is {}, my age next year is {}, my anniversary is {}.' << name << (age+1) << anniversary // '%A, %B %d, %Y') Other operators might be better, but those aren't that commonly used, and I think they show the intents well. Cheers, Ron
participants (5)
-
Alexander Belopolsky
-
Mike Miller
-
Rob Cliffe
-
Ron Adam
-
Vito De Tullio