2

I feel like this would have been asked before, but could not find anything.

In python, if you want to insert a var into a string, there are (at least) two ways of doing so.

Using the + operator

place = "Alaska"
adjective = "cold"
sentence = "I live in "+place+"! It's very "+adjective+"!"
# "I live in Alaska! It's very cold!"

And using a tuple

place = "Houston"
adjective = "humid"
sentence = "I live in %s! It's very %s!" % (place, adjective)
# "I live in Houston! It's very humid!"

Why would one use the tuple method over using +? The tuple format seems a lot more obfuscated. Does it provide an advantage in some cases?

The only advantage I can think of is you don't have to cast types with the latter method, you can use %s to refer to a, where a = 42, and it will just print it as a string, as opposed to using str(a). Still that hardly seems like a significant reason to sacrifice readability.

Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343
Brian C
  • 1,333
  • 3
  • 19
  • 36

2 Answers2

4

For a lot of reasons. One good reason is that not always you can or want to use separated strings, because they are already neatly arranged in a list or tuple:

strings = ["one", "two", "three"]

print "{}, {} and {}".format(*strings)

> one, two and three
heltonbiker
  • 26,657
  • 28
  • 137
  • 252
4

The string % (value, value, ..) syntax is called a string formatting operation, and you can also apply a dictionary, it is not limited to just tuples. These days you'd actually want to use the newer str.format() method as it expands on the offered functionality.

String formatting is about much more than just inserting strings in-between other strings. You'd use it because

  • you can configure each interpolation, based on the type of object you are trying to insert into the string. You can configure how floating point numbers are formatted, how dates are formatted (with str.format()), etc.

  • you can adjust how the values are padded or aligned; you could create columns with values all neatly right-aligned in fixed-width columns, for example.

  • especially with str.format(), the various aspects you can control can either be hardcoded in the string template, or taken from additional variables (the older % string formatting operation only allows for field width and numeric precision can be made dynamic).

  • you can define and store the string templates independently, applying values you want to interpolate separately:

    template = 'Hello {name}! How do you find {country} today?'
    result = template.format(**user_information)
    

    What fields are available can be larger than what you actually use in the template.

  • it can be faster; each + string concatenation has to create a new string object. Add up enough + concatenations and you end up creating a lot of new string objects that are then discarded again. String formatting only has to create one final output string.

  • string formatting is actually far more readable than using concatenation, as well as being more maintainable. Try to use + or string formatting on a multiline string with half a dozen different values to be interpolated. Compare:

    result = '''\
    Hello {firstname}!
    
    I wanted to send you a brief message to inform you of your updated
    scores:
    
        Enemies engaged: {enemies.count:>{width}d}
        Enemies killed:  {enemies.killed:>{width}d}
        Kill ratio:      {enemies.ratio:>{width}.2%}
        Monthly score:   {scores.month_to_date:0{width}d}
    
    Hope you are having a great time!
    
    {additional_promotion}
    '''.format(width=10, **email_info)
    

    with

    result = '''\
    Hello ''' + firstname + '''!
    
    I wanted to send you a brief message to inform you of your updated
    scores:
    
        Enemies engaged: ''' + str(email_info['enemies'].count).rjust(width) + '''
        Enemies killed:  ''' + str(email_info['enemies'].killed).rjust(width) + '''
        Kill ratio:      ''' + str(round(email_info['enemies'].ratio * 100, 2)).rjust(width - 1) + '''%
        Monthly score:   ''' + str(email_info['scores'].month_to_date).zfill(width) + '''
    
    Hope you are having a great time!
    
    ''' + email_info['additional_promotion'] + '''
    '''
    

    Now imagine having to re-arrange the fields, add some extra text and a few new fields. Would you rather do that in the first or second example?

Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343
  • 1
    I did not know about the new way of doing this that allowed you to insert a string using {}, that really does help with readability. Thanks a lot. I'm still a little confused as to the format being use there though. It looks like you are grabbing, the var `count` from the object `enemies`, but then what does the `**emailinfo` refer to? – Brian C Aug 19 '16 at 19:59
  • 1
    @BrianC: `emailinfo` is a dictionary; each key-value is passed into `str.format()` as a separate keyword argument. So `enemies` is one key in the dictionary. String formatting lets you access attributes or index lists or access keys in a mapping too; `.count` is an attribute on the `enemies` value here (so it's not a string, it's an object with attributes here). – Martijn Pieters Aug 19 '16 at 20:55