Python: fstrings

The print function and string formatting

Assigning variables

Let's create three basic variables a, b, and c that are of the data type str, int and float respectively.

In [1]:
a = "hello"
In [2]:
b = 1
In [3]:
c = 1.1

The print function

The print function can be used to print the value of an object as part of the output of a cell. We can look up its docstring using ?.

In [4]:
? print
Docstring:
print(value, ..., sep=' ', end='\n', file=sys.stdout, flush=False)

Prints the values to a stream, or to sys.stdout by default.
Optional keyword arguments:
file:  a file-like object (stream); defaults to the current sys.stdout.
sep:   string inserted between values, default a space.
end:   string appended after the last value, default a newline.
flush: whether to forcibly flush the stream.
Type:      builtin_function_or_method

The positional input arguments are value, ... lets assign value to a str.

In [5]:
print("hello")
hello

We can also assign it to an object name. The value of the object will be printed.

In [6]:
print(a)
hello
In [7]:
print(b)
1
In [8]:
print(c)
1.1

The positional input argument value, ... implies we can print a single value or multiple values.

In [9]:
print(a)
hello
In [10]:
print(a, a)
hello hello

Notice that the keyword input argument sep has a default value of ' ' meaning a space is inserted between each value. This can be explicitly implied and changed to a new value.

In [11]:
print(a, a, sep=" ")
hello hello
In [12]:
print(a, a, sep="-")
hello-hello

The keyword argument end has a default value of \n (new line) which places a new line after the print statement. This can be explicitly implied.

In [13]:
print(a, a, sep="-", end="\n")
print(a, a, sep="+")
hello-hello
hello+hello

Notice that when end is changed to a new value, the two print statements continue on the same line as no \n (new line) is specified.

In [14]:
print(a, a, sep="-", end=":")
print(a, a, sep="+")
hello-hello:hello+hello

The back slash \

The back slash can be used within a str to denote a special character. For example:

  • \n (new line)
  • \t (tab)
  • \\ (back slash)
In [15]:
print("\t",a)
	 hello
In [16]:
print("\n",a)
 hello

The rstr (relative str)

When file paths are copied from the operating system for example C:\Windows\System32 they contain a single back slash. To convert them to a str we must update every back slash to a double back slash (recall the first back slash within a str denotes we are going to insert a special character and the second back slash denotes that the special character is the back slash).

In [17]:
print("C:\\Windows\\System32")
C:\Windows\System32

A relative str or rstr will automatically convert all instances of \ in a file path to \\. To use a rstr, prepend the str with r.

In [18]:
print(r"C:\Windows\System32")
C:\Windows\System32

The type function

The type function can be used to determine the data type of an object. We can look up its docstring using ?.

In [19]:
? type
Init signature:  type(self, /, *args, **kwargs)
Docstring:     
type(object_or_name, bases, dict)
type(object) -> the object's type
type(name, bases, dict) -> a new type
Type:           type
Subclasses:     ABCMeta, EnumMeta, _TemplateMetaclass, _ABC, MetaHasDescriptors, PyCStructType, UnionType, PyCPointerType, PyCArrayType, PyCSimpleType, ...
In [20]:
type(a)
Out[20]:
str
In [21]:
type(b)
Out[21]:
int
In [22]:
type(c)
Out[22]:
float

Inserting variables into a str using str concatenation

Sometimes we will want to print the value of a variable incorporated into a str. We can do this using str concatenation with the + operator.

In [23]:
print("a is"+a+".")
a ishello.

Note that we have to manually specify spaces.

In [24]:
print("a is "+a+".")
a is hello.

When the object is not a str. We have to cast it to a str using the str class.

In [25]:
print("b is "+str(b)+".")
b is 1.
In [26]:
print("c is "+str(c)+".")
c is 1.1.

The fstr (formatted str)

object values can be placed within a str using the a formatted str or fstr. The fstr must be prepended with an f and the object name to be inserted is enclosed with a {}. For example:

In [27]:
print(f"a is {a}.")
a is hello.
In [28]:
print(f"b is {b}.")
b is 1.
In [29]:
print(f"c is {c}.")
c is 1.1.

We can insert multiple objects in each fstr, for example:

In [30]:
print(f"a is {a}, b is {b} and c is {c}.")
a is hello, b is 1 and c is 1.1.

Within the placeholder {object} a format specification can be added by use of a colon :. A letter is used to denote the object data type:

  • s for a `str
  • d for a decimal int
  • f for a float

The str placeholder ns

Let's have a look at the formatting options for a str.

In [31]:
print(f"a is {a}.")
a is hello.

If we just use s the str will print out using the defaults.

In [32]:
print(f"a is {a:s}.")
a is hello.

We can prepend an int n to specify the number of characters the str should specify. By default the number of characters used will be the length of the str. Let's set n to 10.

In [33]:
print(f"a is {a:10s}.")
a is hello     .

Note that this can be used to left justify some printed str.

In [34]:
print(f"a is {a:10s}.")
print(f"a is {a+a:10s}.")
a is hello     .
a is hellohello.

Note that str methods capitalize, upper and lower can be used to format the text of the str.

In [35]:
print(f"a is {a.capitalize():10s}.")
a is Hello     .
In [36]:
print(f"a is {a.upper():10s}.")
a is HELLO     .
In [37]:
print(f"a is {a.lower():10s}.")
a is hello     .

The decimal int placeholder 0nd

Let's now have a look at the formatting options for a decimal int.

In [38]:
print(f"b is {b}.")
b is 1.

If we just use d the int will print out using the defaults.

In [39]:
print(f"b is {b:d}.")
b is 1.

Once again we can specify the number of characters to be displayed using n. Let's set n to 10.

In [40]:
print(f"b is {b:10d}.")
b is          1.

If we want to display leading zeros, we can also prepend n with a 0. Let's use 010.

In [41]:
print(f"b is {b:010d}.")
b is 0000000001.

This can be quite useful for objects such as time and dates.

In [42]:
day = 4
month = 5
year = 2021
In [43]:
print(f"The date is {day}-{month}-{year}.")
The date is 4-5-2021.
In [44]:
print(f"The date is {day:02d}-{month:02d}-{year:04d}.")
The date is 04-05-2021.
In [45]:
hour = 8
minute = 5
second = 7
In [46]:
print(f"The time is {hour}:{minute}:{second}.")
The time is 8:5:7.
In [47]:
print(f"The time is {hour:02d}:{minute:02d}:{second:02d}.")
The time is 08:05:07.

Note there are specific formatting options available for a datetime object.

The float placeholder 0n.mf

Let's now have a look at the formatting options for a float.

In [48]:
print(f"c is {c}.")
c is 1.1.

If we just use f the float will print out using a default of 6 decimal places.

In [49]:
print(f"c is {c:f}.")
c is 1.100000.

Once again we can specify the number of characters to be displayed using n. Let's set n to 10.

In [50]:
print(f"c is {c:10f}.")
c is   1.100000.

Once again if we want to display leading zeros, we can also prepend n with a 0. Let's use 010.

In [51]:
print(f"c is {c:010f}.")
c is 001.100000.

Notice that there are ten characters in 001.100000 and including the character of the decimal point ..

The float is automatically specified to 6 decimal places. This may not be desired, particularly when the float represents a physical value from a measurement. Take for example the ruler below, it has cm markings and divisions for a mm. If a distance measurement of 21 mm is represented as a float in terms of the meter unit. 0.021 m makes much more sense than 0.021000 as the latter implies μm accuracy opposed to the mm accuracy of the measurement.

Let's create a float of the distance and now use a fstr to print it.

In [52]:
distance = 0.021
In [53]:
print(f"The distance is {distance:f} m.")
The distance is 0.021000 m.

We see the distance is displayed with μm precision. We can update the placeholder to specify the number of decimal places using the form 0n.mf where n is the number of characters to display including the decimal point . and m is the precision i.e. the number of characters displayed after the decimal point. Let's set n to 6 and m to 3. This means we will have 6 characters in total, 3 after the decimal point, the decimal point itself and 6-3-1=2 before the decimal point.

In [54]:
print(f"The distance is {distance:06.3f} m.")
The distance is 00.021 m.

Note that it is far more common to specify .mf opposed to 0n.mf.

In [55]:
print(f"The distance is {distance:.3f} m.")
The distance is 0.021 m.

Note that an object of the datatype int can be printed as a float.

In [56]:
print(f"b is {b:.3f}.")
b is 1.000.

The datetime placeholder

In [57]:
import datetime
now = datetime.datetime.now()

For a datetime object, the current format specifiers can be used:

  • %Y year
  • %m month
  • %d day
  • %H Hour
  • %M Minute
  • %S Second
In [58]:
print(f'The time is {now: %H:%M:%S} and the date is {now: %d-%m-%Y}.')
The time is  08:35:22 and the date is  08-05-2021.

The str format method

object values can also be placed within a str using the str format method. The str format method can take a variable number of keyword input arguments. Each keyword input argument kw must also be placed within the str using a {kw} placeholder. For example:

In [59]:
print("a is {kw1}.".format(kw1="hello"))
a is hello.
In [60]:
print("b is {kw2}.".format(kw2=1))
b is 1.
In [61]:
print("c is {kw3}.".format(kw3=1.1))
c is 1.1.

Let's insert the objects a, b and c into a str using:

In [62]:
print("a is {kw1}, b is {kw2} and c is {kw3}.".format(kw1=a, kw2=b, kw3=c))
a is hello, b is 1 and c is 1.1.

We can name the format method keyword input arguments a, b, and c. Recall that these will be local to the function and therefore we can assign the values of these to a, b and c which come from the main workspace.

In [63]:
print("a is {a}, b is {b} and c is {c}.".format(a=a, b=b, c=c))
a is hello, b is 1 and c is 1.1.

It is also possible to use the format method with an optional number of positional input arguments instead. When using positional input arguments, no keyword argument is specified in the placeholder.

In [64]:
print("a is {}, b is {} and c is {}.".format(a, b, c))
a is hello, b is 1 and c is 1.1.

The str format method uses the same str formatting options as the fstr. For example:

In [65]:
print("a is {kw1:10s}, b is {kw2:010d} and c is {kw3:010.3f}.".format(kw1=a, kw2=b, kw3=c))
a is hello     , b is 0000000001 and c is 000001.100.
In [66]:
print("a is {:10s}, b is {:010d} and c is {:010.3f}.".format(a, b, c))
a is hello     , b is 0000000001 and c is 000001.100.

str formatting using the % operator

object values can be placed within a str using C-style syntax. This type of syntax was commonly used for Python 2. In Python 3 the fstr and the str format method are more commonly used as they are more intuitive.

With the C-style syntax a placeholder must be specified within the str for each object (%s for a str, %d for a decimal int and %f for a float). The str is preceded by the % operator which acts on a tuple of the object names to be inserted within the str.

In [67]:
print("a is %s."%(a))
a is hello.
In [68]:
print("b is %d."%(b))
b is 1.
In [69]:
print("c is %f."%(c))
c is 1.100000.

Incorporating these three objects into a str gives:

In [70]:
print("a is %s, b is %d, c is %f."%(a,b,c))
a is hello, b is 1, c is 1.100000.

With exception to the use of % opposed to :the format specification in the placeholders is identical to fstr and the str format method.

In [71]:
print("a is %10s, b is %010d, c is %010.3f."%(a,b,c))
a is      hello, b is 0000000001, c is 000001.100.