Rodolfo
Rodolfo

Reputation: 593

Formatting multiple %s with a single variable

I have a string with unknown number of %s that need to be formatted with a single string.

For instance, if I had the string "%s some %s words %s" and wanted to format it with the word house it should output "house some house words house"

Doing the following gives me an error:

>>> "%s some %s words %s" % ("house")
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: not enough arguments for format string

So, I decided to do the following, which works but seem to be overly complex for such a simple problem.

var = "house"
tup = (var,)
while True:
    try:
        print "%s some %s words %s" % tup
        break
    except:
        tup += (var,)

Is there a more pythonic way of doing this?

Upvotes: 3

Views: 1622

Answers (3)

Taylor D. Edmiston
Taylor D. Edmiston

Reputation: 13016

Here are a few options:

Format string (and Formatter class)

Using str.format is the most pythonic way and pretty simple to read. Either style is popular:

Position arguments

'{0} some {0} words {0}'.format('house')

Named arguments

'{word} some {word} words {word}'.format(word='house')

In a comment you mentioned preserving the original format string because of other legacy code. You could hack around that like so:

'%s some %s words %s'.replace('%s', '{0}').format('house')

(I don't recommend it but you could "short circuit" this idea line by using 'house' in the replace call instead of '{0}'.)

That said, I really think changing the template string in the first place is a better idea.

Template strings

One more alternative comes to mind after glancing at the string docs: the older string.Template class. By default it substitutes $-based values, but you can subclass it overriding the delimiter character. For example:

class MyTemplate(Template):
    """
    Overriding default to maintain compatibility with legacy code.
    """
    delimiter = '%'


t = MyTemplate('%s some %s words %s')
t.substitute(s='house')

Remember this is less common but you could write it once and re-use it every time you work with a string like this (assuming there's only one input value being substituted in). Writing it once is Pythonic at least!

Literal string interpolation

In Python 3.6, Ruby-style string interpolation is another option that the community hasn't come to a consensus on yet. For example:

s = 'house'
f'{s} some {s} words {s}'

Upvotes: 5

Def_Os
Def_Os

Reputation: 5457

Why not use format?

"{0} some {0} words {0}".format("house")

Upvotes: 1

kindall
kindall

Reputation: 184091

If you know for sure you're subbing %s you can do it like this:

var = "house"
tup = (var,)
txt = "%s some %s words %s"

print txt % (tup * txt.count("%s"))

But a better solution is to use str.format() which uses a different syntax, but lets you specify items by number, so you can reuse them:

var = "house"
txt = "{0} some {0} words {0}"

print txt.format(var)

Upvotes: 5

Related Questions