Python Forum
[Basic] f-string, string format, and string expressions
Thread Rating:
  • 1 Vote(s) - 5 Average
  • 1
  • 2
  • 3
  • 4
  • 5
[Basic] f-string, string format, and string expressions
#1
The bad way
This is called concatenation. In other languages this is considered okay. In Python it is not. Don't do this in Python. Its clunky, its unpythonic, harder to maintain, error prone, and more keystrokes in general. You are also missing out on the simplicity of Python.
BAD = 'bad'
PYTHON = 'Python'
stringer = 'This is a '+ BAD +' thing to do in ' + PYTHON + 'in any form or fashion')
What are my options?
There are three ways to format strings. The first is the Expression (which it's character is known for as %). This is outdated. The second is the newer technique: the format method str.format(). Lastly there is the f-string. This is an adaption of the format method and the most preferred way to format strings as of this writing. These will be explained more in detail in the same order below.

Format Expressions
This is the old method in which Python2.x relied upon. If you are using python3.x you should not be using this method. It is a very real possibility that it can be depreciated in coming python versions. For backwards compatibility is the only reason it is in this tutorial.
The % operator when applied to strings provides a way to format a string according to it's format definition. The way it is applied is like so: 
>>> s = 'There are %i %s to format a string' % (2, 'ways')
>>> s
'There are multiple ways to format a string'
When you plug in more than two values into the string they need to be within parenthesis. The %i gets replaced by the integer 2 and the %s gets replaced by string 'ways'. If you do not input the correct definition for the corresponding value you will get an error. The below code shows an example of attempting to input two integers where one of them is a string. 
>>> 'There are %i %i to format a string' % (2, 'ways')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: %i format: a number is required, not str
Format Method
This is the new method that python3.x relies on.
Unlike the format expressions, you can use the format method to plug in any data to a string without specifying it's definition. This same technique is applied to f-strings as well. So continue to read this section if you are only planning on using f-strings.
>>> 'some data: {} {} {}'.format(1.4, 5, 'stringer')
'some data: 1.4 5 stringer'
As you can see. The type of data it is, does not matter. Here, the {} indicate the definition of whatever is in the order of the format()'s arguments. By default empty curly brackets {} plug format()'s arguments into the string at their position they are in format(). You can also change this order of postion. 
>>> 'some data: {2} {1} {0}'.format(1.4, 5, 'stringer')
'some data: stringer 5 1.4'
You can also plug the values in by keyword. 
>>> temp = '{header} {body}, and good{footer}'
>>> temp.format(header='hello', body='Metul Burr', footer='bye metulburr')
'hello Metul Burr, and goodbye metulburr'
 Or you can do them both by position and keyword. 
site = '{w3}{0}{tld}'
>>> site.format('metulburr',w3='www.',tld='.com')
'www.metulburr.com'
This is simply plugging variables into various positions of the string. That is all we did here in different ways to give an example of how to do it. Next we format the variables even further with the format method.

Specific Formatiing
Yes. It can get more complicated. Format method has an embedded mini-language inside itself in which it can format it further. The format for {} inside a string is: {fieldname!convertionflag:formatspec}
  • Fieldname is a number or keyword naming an argument, followed by optional ".name" attribute or "[index]" component references.
  • Conversionflag can be r, s, or a to call repr, str, or ascii built in functions on the value.
  • Formatspec specifies how the value should be presented (width, alignment, padding, decimal precision, etc.)
Within the formatspec a subcategory of: [[fill]align][sign][#][0][width][.precision][typecode] gives the specifications of how it should be presented. Align can be <, >, =, or ^, for the left alignment, right alignment, padding after a sign character, or centered alignment. The formatspec also contains a nested {} format strings with field name only. 

{0:10} means the first positional argument in a field of 10 characters wide, {1:<10} means the second positional left-justified in a 10 character-wide field, and {0.platform:>10} means the platform attribute of the first argument right-justified in a 10 character-wide field
>>> '{0:10} = {1:10}'.format('spam', 123.4567)
'spam       =   123.4567'
>>> '{0:>10} = {1:<10}'.format('spam', 123.4567)
'      spam = 123.4567  '
>>> import sys
>>> '{0.platform:>10} = {1[item]:<10}'.format(sys, dict(item='laptop'))
'     linux = laptop 
The following is a few more examples:
>>> num = 3.141592653589793
>>> '{:.2f}'.format(num) #drop after second decimal
'3.14'
>>> '{:.3f}'.format(num) #drop after 3rd decimal
'3.142'
>>> '{:010.3f}'.format(num) #give us 10 characters filled with zeros in empty spaces, drop after 3 decimal
'000003.142'
>>> '{:10.2f}'.format(num) #give us 10 characters, drop after 2 decimals
'      3.14'
>>> '{:30}'.format(num) #give us 30 characters
'             3.141592653589793'
>>> '{:<30}'.format(num)
'3.141592653589793             '
>>> '{:,}'.format(123456789) #insert commas
'123,456,789'
>>> '{0:X}, {1:o}, {2:b}'.format(255,255,255) #hex, octal, and binary formats
'FF, 377, 11111111'

>>> '{0:.2f}'.format(1 / 3.0) #hardcoded
'0.33'
>>> '{0:.{1}f}'.format(1 / 3.0, 4) #take values from arguments
'0.3333'

'
More in depth information here about the mini-language inside format method.

Though you may not understand everything about the mini-language, it is vital to at least use it to plug in variables as shown in the first example t bare minimum.


F-strings

On Python3.6 and higher there is the new formatted string literals or rather just f-strings. It uses the same functionality as str.format() without the format method. You can still use the old format method, but most people prefer to use f-strings as it simplifies it and makes it shorter. It also is faster in speed.

>>> name = 'metulburr'
>>> 'My name is {}'.format(name)
'My name is metulburr'
becomes
>>> name = 'metulburr'
>>> f'My name is {name}'
'My name is metulburr'
Note that the variable name is not injected into the string manually.
from PUP 498
Quote:The expressions that are extracted from the string are evaluated in the context where the f-string appeared. This means the expression has full access to local and global variables. Any valid Python expression can be used, including function and method calls.

name = 'metulburr'

def func():
   name = 'tom'
   print(f'My name is {name}')

func()
Output:
My name is tom
as well as the use of a function for example
>>> def namer():
...     return 'metulburr'
... 
>>> f'My name is {namer()}'
'My name is metulburr'
In fact you can put any expression in between the {}
>>> f'How can I determine {1+1} ?'
'How can I determine 2 ?'
A previous example converted to fstrings:
>>> w3 = 'www.'
>>> name = 'metulburr'
>>> tld = '.com'
>>> site = f'{w3}{name}{tld}'
>>> site
'www.metulburr.com'
You can also use f-strings in combination with specific formating
>>> from math import pi  # pi ~ 3.141592653589793
>>> '{0:.2f}'.format(pi)
'3.14'
becomes
>>> from math import pi  # pi ~ 3.141592653589793
>>> f'{pi:.2f}'
'3.14'
As a wrap up, f-strings are in general are just better. They are the future of string formating. If a single string gets too complex you can simplify it by using function and variables along with the f-string. Don't pack everything into a string to make it too complex.

underscores in numeric literals. Another python 3.6 addition
>>> i = '{:_}'.format(1000000)
>>> i
'1_000_000'
>>> int(i)
1000000
Recommended Tutorials:


Possibly Related Threads…
Thread Author Replies Views Last Post
  Comprehension Expressions micseydel 0 4,399 Oct-10-2016, 03:28 PM
Last Post: micseydel

Forum Jump:

User Panel Messages

Announcements
Announcement #1 8/1/2020
Announcement #2 8/2/2020
Announcement #3 8/6/2020