-
-
Notifications
You must be signed in to change notification settings - Fork 31.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Allow auto-numbered replacement fields in str.format() strings #49487
Comments
3.x str.format() format strings denote replacement fields with braces For simple sequential positional replacements, such as: This proposal is currently all or nothing for simplicity of description This idea was posted today on Python-ideas thread "String formatting and |
It's easy enough to implement. Although the 'all-or-nothing' aspect is a Maybe the best way to do this is to first create a string.Formatter From the description, I'm presuming we'd want: |
'{d}{s}{f}'.format(3, 'foo', 3.14) is possibly unclear, '{#d}{#s}{#f}'.format(...) |
I am net yet fluent in format method. I meant ":" where "#" appeared. Anyway, I think you need the colon. If from you make the argument number implicit and remove the colon you'd get print('{9}'.format(33)) which does and should raise IndexError. |
How is: more unclear than: But the more I think about it, the more I think it would have to be: |
+1 for the general idea from me too, assuming that all the details can Is it worth opening a discussion about this on comp.lang.python? |
The attached file is a mostly working version that inherits from
These are all a function of me being too lazy to write a complete Admittedly this isn't a drop-in replacement for ''.format(), but it |
Unfortunately, (I agree that the syntax for format() strings is exceedingly tedious) On the other hand, |
Answering first question msg81873. Without colon separator, this might be considered confusing: >>> (
... '{d}{s}{f}{f}'.format(3, 'foo', 3.14, 2.72),
... '{d}{s}{f}{f}'.format(d=3, s='foo', f=3.14)
... )
('3foo3.1400002.720000', '3foo3.143.14') |
Right. The colon would be required if there's a format specifier. Or an "{!r}{:f}{!s:^10}".format('foo', 3, 10) I've attached a new version that includes format specifiers. |
All I am requesting is that >>> '%s %s %s' % (3, 'pi', 3.14)
'3 pi 3.14'
>>> '{0} {1} {2}'.format(3, 'pi', 3.14)
'3 pi 3.14' do today (3.0). I should note that the difference between typing {}, which is easy, and |
Terry J. Reedy wrote:
> Terry J. Reedy <tjreedy@udel.edu> added the comment:
>
> All I am requesting is that
> '{} {} {}'.format(3, 'pi', 3.14) work as
>
>>>> '%s %s %s' % (3, 'pi', 3.14)
> '3 pi 3.14'
>>>> '{0} {1} {2}'.format(3, 'pi', 3.14)
> '3 pi 3.14'
>
> do today (3.0). My string.Formatter subclass (attached to this bug report) does do this: $ ./python.exe
Python 2.7a0 (trunk:69516, Feb 11 2009, 14:30:31)
[GCC 4.0.1 (Apple Inc. build 5465)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> from auto_number_formatter_1 import MyFormatter
>>> f = MyFormatter()
>>> f.format('{} {} {}', 3, 'pi', 3.14)
'3 pi 3.14'
>>> This is just for vetting the concept, if it's accepted I'll modify The talk about '{:d}' and the like is just to make sure all the cases
Agreed. |
auto_number_formatter_2.py lets you experiment with this with a syntax $ ./python
Python 2.7a0 (trunk:69608, Feb 14 2009, 04:51:18)
[GCC 4.1.2 20070626 (Red Hat 4.1.2-13)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> from auto_number_formatter_2 import formatter as _
>>> _('{} {} {}').format(3, 'pi', 3.14)
'3 pi 3.14'
>>> It still doesn't handle escaping '{' and '}', but is otherwise complete. |
Okay, one last version. This one lets you use object access within the >>> from auto_number_formatter_3 import formatter as _
>>> _('{} {} {}').format(3, 'pi', 3.14)
'3 pi 3.14'
>>> _('{:#b} {!r:^10} {.imag}').format(3, 'pi', 3j+1)
"0b11 'pi' 3.0" So not it lets you add in format specifiers, conversion specifiers, and |
I'm attaching a patch that delivers the basic functionality in DO NOT USE THIS PATCH IN ANY SERIOUS WORK It doesn't implement all of the needed functionality, it probably has a In particular, it doesn't handle anything other than empty braces If we reach a consensus that the feature should be added, I can probably $ ./python.exe
Python 2.7a0 (trunk:70244M, Mar 8 2009, 16:54:23)
[GCC 4.0.1 (Apple Inc. build 5465)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> '{} {} {}'.format(1, 3.4, 'test')
'1 3.4 test'
>>> '{} {1}'.format(1, 2)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: cannot switch from automatic field numbering to manual field
specification
>>> |
Also note that this patch causes a few tests to fail, since they're |
Please go ahead and finish this. I'm glad this is going in! |
Excellent feature - with this, I would actually see some hope for |
Would someone like to point the python-ideas discussion which |
Terry covered how to document the feature in his original description of "If the index/name is left out for all replacement fields, then the |
It may also be worth explicitly stating the following in the docs: "Note This proposal is also significantly better defined than the rather >>> "%s %(name)s" % dict(name="Hmm")
"{'name': 'Hmm'} Hmm"
>>> "%s %(name)s %s" % dict(name="Hmm")
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: not enough arguments for format string
>>> "%s %(name)s %s" % (dict(name="Hmm"), "dodgy")
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: format requires a mapping |
I'm thinking of allowing you to mix keywords and auto-numbering, but not >>> '{:{fmt}} {:{fmt}}'.format(3.1415, 2.71828, fmt='1.4f')
'pi=3.1415 e=2.7183' Unfortunately the ':' is required, because if it's not there you have 2 |
Copy and paste error. That should be: >>> 'pi={:{fmt}} e={:{fmt}}'.format(3.1415, 2.71828, fmt='1.4f')
'pi=3.1415 e=2.7183' |
Should string.Format also support auto-numbering? It seems like it should, but I'm not convinced it's possible without |
Not sure if that's worth it -- doesn't sound like the people who would |
(I meant that as a reply to the {:{fmt}} example, but it applies to your |
I believe this patch is complete. I need to add tests and documentation, Here's the normal case:
>>> '{} {}'.format('test', 0)
'test 0'
It also handles error checking:
>>> '{1} {}'.format('test', 0)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: cannot switch from manual field specification to automatic
field numbering
>>> '{} {1}'.format('test', 0)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: cannot switch from automatic field numbering to manual field
specification
You can use named fields along with auto-numbered fields:
>>> '{test} {}'.format(1, test=2)
'2 1'
You can nest either named or auto-numbered fields:
>>> '{:^{}}'.format('x', 10)
' x '
>>> 'pi={:{fmt}} {:{fmt}}'.format(3.1415, 2.71828, fmt='1.4f')
'pi=3.1415 2.7183'
Attribute access is supported:
>>> '{.__abs__}'.format(0)
"<method-wrapper '__abs__' of int object at 0x85db8f8>"
As is subscripting:
>>> '{[x]}'.format({'x':4})
'4'
>>> '{[1]}'.format([1, 2])
'2' I'll work on the tests over the weekend, then commit to trunk and py3k. We need to decide what to do about string.Formatter (which I just |
About '{:{fmt}}' and other wacky combinations, like '{.__doc__}': It's much easier and cleaner in the code to allow these cases than it I suggest leaving them in. They might be useful, and it makes the As for string.Formatter, I agree we should leave it alone. I'd be |
OK, if allowing it is simpler, I'm all for allowing it! (I thought it
OK. |
Only Formatter.format_field() is particularly hard to override at the That said, I think it's OK for string.Formatter to lag the actual |
Committed: The docs still need updating. If anyone with more knowledge of the |
Either Brandl or Peterson can and typically will change the .rst source field_name ::= (identifier | integer) ("." attribute_name | "[" to (in essence) field_name ::= (identifier | integer | ) ("." attribute_name | with the proviso that integers and blanks not be mixed in the same field_name ::= ((identifier | integer) ("." attribute_name | "[" (with the same proviso). The existing doc text after the grammar box is slightly ambiguous or |
I implemented this one: Which I would have written as: Not that it matters, of course. And the proviso is correct: blanks and integers cannot be mixed in the Thanks for looking at this! |
Terry, are you still interested in documenting this (please say yes!)? Thanks. |
Yes, added to 'do in next few days' list. |
Terry J. Reedy wrote:
Thanks so much. |
Suggested doc change for
Note: 'element_index' should be linked to its definition just as, for
The *field_name* itself begins with an *arg_name* that is either a
|
Thanks, Terry. Your changes look reasonable to me. Can you commit them, |
I am not a committer and cannot make patches. However, I did download |
PS. I first edited |
Thanks, Terry. I think the only changes I'll make are: arg_name: ( And leave: |
Documentation changes checked into trunk in r71788 and py3k in r71790. Issue closed. |
Note: these values reflect the state of the issue at the time it was migrated and might not reflect the current state.
Show more details
GitHub fields:
bugs.python.org fields:
The text was updated successfully, but these errors were encountered: