Wolph
Wolph

Reputation: 80081

Python string interpolation using dynamic length strings (using *) with keyword arguments (not `string.format`)

For a legacy system that's in use in quite a few places with the string interpolation system I need to implement some code that formats a string with a specific length. I am aware that a rjust or ljust can solve this, but I'm trying to answer the question whether this is possible with the standard string interpolation system.

Examples:

>>> '%0*d' % (5, 3)
'00003'
>>> '%(value)05d' % dict(value=3)
'00003'

Now the question is, how can I combine these two?

My failed attempts:

>>> '%(value)*d' % dict(value=(5, 3))
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: * wants int
>>> '%(value)*d' % dict(value=3)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: not enough arguments for format string
>>> '%(value)*d' % {'*': 5, 'value': 3}
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: not enough arguments for format string
>>> '%(value)*d' % {'*value': 5, 'value': 3}
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: not enough arguments for format string

The question is: how can the asterisk and keyword arguments be combined using string interpolation?


Note: str.format is not an answer to this question, I'm not looking for alternatives but simply to answer the question whether this is possible or not. Replacing string interpolation with str.format would require many users of the current library to modify the function calls which is a unfavourable option for the near future.

Upvotes: 2

Views: 680

Answers (1)

jonrsharpe
jonrsharpe

Reputation: 122116

No, you can't do this. Per the documentation (emphasis mine):

  1. Minimum field width (optional). If specified as an '*' (asterisk), the actual width is read from the next element of the tuple in values, and the object to convert comes after the minimum field width and optional precision.

You need to be passing a tuple, not a dictionary, as values to use the * field width. This is then made explicit:

When the right argument is a dictionary (or other mapping type), ... no * specifiers may occur in a format (since they require a sequential parameter list).

Upvotes: 2

Related Questions