Page 1 of 1

Python String Formatting

#1 atraub  Icon User is offline

  • Pythoneer
  • member icon

Reputation: 828
  • View blog
  • Posts: 2,235
  • Joined: 23-December 08

Posted 03 May 2015 - 01:34 PM

Python String formatting is an interesting topic. There are 3 basic ways to format a string. I'll be talking about them in ascending order of preference. For the purposes of this discussion, we'll also be writing a small snippet of code that uses each style. The code will have identical output for identical inputs with each style which will make it a fair comparison. This tutorial makes no assumption as to whether you're using python 2 or 3, but it does assume that if you're using Python 2, you're using Python 2.6 or later. Thus, if you're using something like Python 2.5, the last style won't work. As for our sample function, it'll be relatively simple. It will take your name, a product's name, and a product's pre-tax value as inputs, it will apply tax to that product, and then output a message. Example:
>>> styleA("Adam","Oreo",2.99)
"Adam, the product 'Oreo' costs $3.37 after tax. Thanks for shopping with us, Adam! Enjoy your Oreos"


Obviously this is a contrived example. It should be contrived as we're trying to pinpoint specific functionality and don't want to get bogged down with additional superfluous code that doesn't add to the tutorial. So, let's begin with styleA.



Style A.) Concatenation
def styleA(yourName, productName, value):
    tax = 1.127 #for simplification I include the 1
    return yourName+", the product '"+productName+"' costs $"+str(round(value*tax,2))+" after tax. Thanks for shopping with us, "+yourName+"! Enjoy your "+ productName +"s"
This style is probably the most common style among beginners - it's also the worst. It offers the fewest options in terms of formatting and is ugly to look at. To put it bluntly, you simply cast everything to a string and then it's a simple matter of string concatenation. From a performance standpoint, this is likely going to be your slowest option as string concatenation can be a bit ugly. Further, if you want to apply any sort of formatting to your strings, you'll either have to apply additional function calls to the input values or apply some functions or slicing to the value after it's been cast to a string. In the above example, you see that we wanted to round the price to two decimal places. To do that, I felt that the best method would be to round the float value to two decimal places and then cast it to the string. For the untrained eye, this may look fine but to a more experienced programmer, this certainly begs to be improved upon. On the positive side, it is very easy to tell what variables go where.



Style B.) Substitution
def styleB(yourName, productName, value):
    tax = 1.127 #for simplification I include the 1
    return "%s, the product '%s' costs $%.2f after tax. Thanks for shopping with us, %s! Enjoy your %ss"%(yourName, productName, value*tax, yourName, productName)
This style has been around for quite a while. It exists in other languages such as C and Java and is very well known to the more seasoned developers. In this style, we use '%s' in a spot where we have a string we want to substitute in, we use '%f' for a float. You'll notice that the float is %.2f. This means that we want it to round to two decimal places. There are other format operators such as %i for integer. You'll notice at the end of the string we have another percent symbol and a tuple containing the values we want to substitute in. If there's only 1 value, you don't need to put it into a tuple, but it really doesn't hurt to put it into 1 most of the time, so you can probably consider it a best practice to go ahead and throw whatever you're subbing into a tuple regardless. One annoyance you'll immediately notice is that in order to use this style, we must know what types we're passing in. Thus we need to know if it's an integer, string, float, etc... or we'll get an error. This is a serious shortcoming when one considers that Python is a language that boasts duck typing! This style is generally considered good except for one additional problem – it's deprecated! This means that at some point, Python will theoretically drop support for it in favor of a newer, better style. You'll likely see many tutorials that still use this method for quite a while. If you're like me and want to be on the cutting edge and show that you know Python well, there's only 1 way to do it:



Style C.) String Format Function (ie. The newer and better style)
def styleC(yourName, productName, value):
    tax = 1.127 #for simplification I include the 1
    return "{0}, the product '{1}' costs ${2:.2f} after tax. Thanks for shopping with us, {0}! Enjoy your {1}s".format(yourName, productName, value*tax)
This style is the least well known because it's on the newer side only having been introduced in Python 2.6. In this style, we use braces {} to denote where a substitution will be made. You'll notice that in my function, I include an integer in the braces. These integers correspond to the position of the value passed into the format function. It's not strictly necessary to pass integers in, but I usually use it because it makes it easier to see which value goes in which position in longer strings. By using the integer in the braces, we're also able to reuse variables passed into the function by reusing their integer index. In this example, you notice that we use the “yourName” and “productName” variables twice, yet only need to pass them into the function once. This specific example was chosen because it shows how much cleaner and simpler the code is with the format method. With substitution, we have no choice but to pass the variables in multiple times, similar to the concatenation method. You'll also notice that the code looks very similar to the substitution method. You may even be upset to notice that I had to incorporate the 'f' for float in there when I specifically said that needing to know the type was a weakness of the substitution method! Well, we don't NEED to know the types with the format method, but if we do want to do decimal place rounding with it, we need to know it's a float – but that should be obvious! If we have to round decimal places, it's going to be a float regardless (as far as string formatting is concerned, anyways). The format function has lots of other cool features if we use the colon. Of course {:.xf} would say that we want to round the value to x decimal places but you probably realized that. By saying {:+f} we say that we want the number to include a +/- sign, but saying {:-f} we say that we want the sign to be used only for negative numbers (default behavior), and {: }(there's a space there) we want a blank space left in front of positive numbers and the negative sign to be present in front of negative ones. Another example is {:,} which says that a number should have commas placed into it, for example
>>> '{:,}'.format(1234567890)
'1,234,567,890'

Another simple example is adding padding to strings to make sure that all strings are the same width:
>>> toPrint = ["hi","I","got","it"]
>>> x = "{:4} other stuff"
>>> for word in toPrint:
    print(x.format(word))

hi   other stuff
I    other stuff
got  other stuff
it   other stuff
>>> x = "{:>4} other stuff"
>>> for word in toPrint:
     print(x.format(word))
     
  hi other stuff
   I other stuff
 got other stuff
  it other stuff
>>> 


This sort of thing is extremely useful when printing out tables.

There's a lot more that can be done with the format method and I strongly suggest you read the docs and learn more about it.

You can check the official docs.
Or plenty of other great resources such as this one.

This post has been edited by atraub: 03 May 2015 - 04:27 PM


Is This A Good Question/Topic? 2
  • +

Page 1 of 1