131

I have a string of this form

s='arbit'
string='%s hello world %s hello world %s' %(s,s,s)

All the %s in string have the same value (i.e. s). Is there a better way of writing this? (Rather than listing out s three times)

Goutham
  • 2,759
  • 9
  • 30
  • 36
  • Duplicate: http://stackoverflow.com/questions/543399/python-string-formatting – bignose Mar 23 '10 at 13:07
  • 3
    This `%` string operator will be "deprecated on Python 3.1 and removed later at some time" http://docs.python.org/release/3.0.1/whatsnew/3.0.html#pep-3101-a-new-approach-to-string-formatting now I wonder what is the most advised way for both version compatibility and security. – cregox Apr 30 '10 at 00:34
  • 2
    @Cawas I know this is pretty late, but I like using `str.format()`. Ex.: `query = "SELECT * FROM {named_arg}"; query.format(**kwargs)`, where `query` is the format string and `kwargs` is a dictionary with keys matching the `named_arg`s in the format string. – Edwin May 14 '12 at 02:36
  • @Edwin not too late. So, basically same thing from the accepted answer, from Adam, i see. – cregox May 14 '12 at 13:45
  • 4
    @Cawas Yeah, except Adam used tuple notation, where `{0}`, `{1}`, `{2}` and so on correspond to tuple indices `0`, `1`, and `2`, respectively. Alternatively, it's also possible to name the args (like `{named_arg}`) and set each one in the format method, like so: `'Hi {fname} {lname}!'.format(fname='John', lname='Doe')` – Edwin May 16 '12 at 04:07
  • You can mix and match between number format (`{0}`) and name format (`{named_args}`), but I'd recommend that you just stick to one or the other, since A) I don't know the consequences of mixing and matching, and B) you won't have to do complicated mental gymnastics and it makes it easier to read, debug, and extend code later on. – Edwin May 16 '12 at 04:16
  • 2
    @bignose You have marked both questions duplicates of one another its like http://www.google.com/search?source=ig&rlz=&q=recursio#q=recursion&spell=1&sa=X&ei=1IZmUcepBMLYrQeCr4CACQ&ved=0CCoQBSgA&bav=on.2,or.r_qf.&bvm=bv.45107431,d.bmk&fp=722769dafe3ca9b1&biw=1366&bih=643 – abhi Apr 11 '13 at 09:48
  • @Edwin I know this is pretty late, but that is how SQL injection happens. I hope that isn't something you ever do in production code. – Singletoned Oct 24 '13 at 12:02

6 Answers6

230

You can use advanced string formatting, available in Python 2.6 and Python 3.x:

incoming = 'arbit'
result = '{0} hello world {0} hello world {0}'.format(incoming)
dolphin
  • 1,192
  • 10
  • 27
Adam Rosenfield
  • 390,455
  • 97
  • 512
  • 589
  • 22
    ~my personal preference, go for kwargs style `result = '{st} hello world {st} hello world {st}'.format(st=incoming)` – nehem Mar 09 '15 at 09:59
50
incoming = 'arbit'
result = '%(s)s hello world %(s)s hello world %(s)s' % {'s': incoming}

You may like to have a read of this to get an understanding: String Formatting Operations.

Peterino
  • 15,097
  • 3
  • 28
  • 29
mhawke
  • 84,695
  • 9
  • 117
  • 138
  • 1
    Nice. Had forgotten about this. locals() will do as well. – Goutham Aug 04 '09 at 03:50
  • 2
    @Goutham: Adam Rosenfield's answer might be better if you're Python version is up to date. – mhawke Aug 04 '09 at 03:53
  • It is actually. Iam still getting used to the new string formatting operations. – Goutham Aug 04 '09 at 03:57
  • 3
    even better, you can multuply the base string: '%(s)s hello world '*3 % {'s': 'asdad'} – dalloliogm Aug 04 '09 at 12:04
  • s is missleading as variable name here and don't forget that the 's' or another formatting option (d, d03, ...) is manadatory after the %() pattern. '%(s) hello' doesn't work '%(s)s hello' does. – gturbo Jul 08 '22 at 12:42
18

You can use the dictionary type of formatting:

s='arbit'
string='%(key)s hello world %(key)s hello world %(key)s' % {'key': s,}
Lucas S.
  • 13,391
  • 8
  • 46
  • 46
14

Depends on what you mean by better. This works if your goal is removal of redundancy.

s='foo'
string='%s bar baz %s bar baz %s bar baz' % (3*(s,))
jjames
  • 666
  • 5
  • 7
4

Fstrings

If you are using Python 3.6+ you can make use of the new so called f-strings which stands for formatted strings and it can be used by adding the character f at the beginning of a string to identify this as an f-string.

price = 123
name = "Jerry"
print(f"{name}!!, {price} is much, isn't {price} a lot? {name}!")
>Jerry!!, 123 is much, isn't 123 a lot? Jerry!

The main benefits of using f-strings is that they are more readable, can be faster, and offer better performance:

Source Pandas for Everyone: Python Data Analysis, By Daniel Y. Chen

Benchmarks

No doubt that the new f-strings are more readable, as you don't have to remap the strings, but is it faster though as stated in the aformentioned quote?

price = 123
name = "Jerry"

def new():
    x = f"{name}!!, {price} is much, isn't {price} a lot? {name}!"


def old():
    x = "{1}!!, {0} is much, isn't {0} a lot? {1}!".format(price, name)

import timeit
print(timeit.timeit('new()', setup='from __main__ import new', number=10**7))
print(timeit.timeit('old()', setup='from __main__ import old', number=10**7))
> 3.8741058271543776  #new
> 5.861819514350163   #old

Running 10 Million test's it seems that the new f-strings are actually faster in mapping.

Community
  • 1
  • 1
user1767754
  • 23,311
  • 18
  • 141
  • 164
3
>>> s1 ='arbit'
>>> s2 = 'hello world '.join( [s]*3 )
>>> print s2
arbit hello world arbit hello world arbit
Yatharth Agarwal
  • 4,385
  • 2
  • 24
  • 53
  • I guess that the example in the question was not about 'hello world' repeated, but a real template with no duplication. That's why I downvoted. – Gra Jan 16 '13 at 08:46