Using Arithmetic Operators on Python Strings

Python lets developers use high-level syntax to perform robust string operations via arithmetic operators. There are some restrictions as well as some common pitfalls. Uncovering some of each will help avoid application errors and in some cases even lower memory use!
python string arithmetic operators alpharithms

Python allows developers to use common arithmetic operators on strings. This high-level manipulation of textual data is one of the many reasons Python has surged in popularity. One example of this is the ability to use arithmetic operators to manipulate strings in Python.

While convenient, there are some limitations to using arithmetic operators such as the plus, minus, plus-equal, and even multiplication operators on strings. For example, multiplying a string by a float will result in TypeError: can’t multiply sequence by non-int of type ‘float’ exception.

Highlights

In this article, we look at some use cases for applying arithmetic operators to Python strings. The discussion will include some common cases, advanced cases, and also common issues. By the end, we will cover the following:

  1. Basic string concatenation with arithmetic operators.
  2. Which operators aren’t able to be used in string operations.
  3. Novel means of applying the multiplication operator to generate copies of strings.
  4. How operator precedence still applies to string operations.
  5. Tips for using arithmetic operators on user input.
  6. How bytearray objects can mutate strings.

Before we dive in, let us first consider the nature of Python strings. Namely, we will briefly discuss how Python strings are immutable, what that means, and the implications this has on performing string-based arithmetic operations.

Quick Intro: Understanding Python Strings

Python strings are different from strings in many other languages. Without diving deeply into the details, it is important to note the following points about Python strings:

  1. Python strings are immutable. Changing a string requires making a copy.
  2. Strings are arrays (list) objects whereby each individual character can be accessed via index-notation as [i] where i is a numerical index into the array (list.)
  3. Numerical user input is converted to a string and must be typecast to the intended format before arithmetic operations can be accurately applied.

Example 0: Strings are Immutable

This is not an example of multiplying, adding, or subtracting strings. However, this point is so essential to understanding how strings are stored and accessed in Python that it must be discussed. Consider the following example:

# example of number mutability
a = 5
print(a)

a += 1
print(a)

# output
5
6

This shows a variable a being assigned an integer value of 5 then, via the += operator (equivalent to a = a + 1) the value is “incremented” by 1 resulting in a final value of 6. This is confirmed via the output from the 2 print statements. In most other programming languages it would be insane to consider doing such an operation to a string. Let’s see how Python handles it:

# Create an example string
s1 = "alpharithms"
print(s1)

# concatenate some text
s1 += " is cool."
print(s1)

# output
alpharithms
alpharithms is cool.

Here we see additional text added to the s1 variable. It seems like we are mutating a string but really we are not. Rather, we are simply reassigning a new value to the variables s1. Let’s see what happens if we try to mutate a string directly in Python:

# create a string
s1 = "alpharithms"

# attempt to remove the s from the end
s1[-1] = ""

TypeError: 'str' object does not support item assignment

Here we get our first glimpse at the immutable nature of Python strings. A TypeError exception is raised when trying to directly manipulate a value contained in a Python string array. This is in stark contrast to how one can manipulate arrays of numerical values — or even arrays of characters. Consider the following code:

# change single character
a1 = ['a', 'l', 'p', 'h', 'a', 'r', 'i', 't', 'h', 'm', 's']
a1[-1] = "\0"
print(a1)

# change integer item
a2 = [1, 2, 3, 4, 5]
a2[0] = 6
print(a2)

# Output
['a', 'l', 'p', 'h', 'a', 'r', 'i', 't', 'h', 'm', '\x00']
[6, 2, 3, 4, 5]

Here we see the output reflect our changes without any exception being raised. This kind of illustrates how Python strings are “special” arrays in that their contained data cannot be manipulated. For a deeper dive, read this article. Simple recognition of the immutability of Python strings is enough for our discussion here.

Example 1: Arithmetic Operator-Based Concatenation

Python allows the use of arithmetic operators to be used for string manipulation. This allows the addition, subtraction, and even multiplication of strings to take place via common operators such as + and  *, as well as the assignment operator, but not -= or *=. We’ll take a look at those last cases in a moment. For now, let’s consider the others:

# creates a string
a1 = "alpharithms"

# create a new string with extra text
a2 = a1 + " is cool"
print(a2)

# use assignment operator to do the same
a1 += " is cool"
print(a1)

# output
alpharithms is cool
alpharithms is cool

Here we see the output to be identical whether we explicitly add a new string via assignment to a new variable a2 or implicitly via the += operator (assigning a new value to the initial variables a1.) Let’s see how some other arithmetic operators hold up in this approach:

subtraction

# Subtraction and multiplication don't always work
b1 = "alpharithms"
b2 = b1 - "s"
print(b2)

# Output
TypeError: unsupported operand type(s) for -: 'str' and 'str'

b1 = "alpharithms"
b1 -= "s"
print(b1)

# Output
TypeError: unsupported operand type(s) for -=: 'str' and 'str'

Here we see the same TypeError exception being raised. Clearly, the subtraction operator doesn’t work well with strings. Division and multiplication operations generate similar exceptions. However, multiplication-based string manipulation is possible in another way.

Example 2: Multiplication-Based String Manipulation

Multiplication is an edge case whereby Python provides some extended features. Similar to subtraction and division, the multiplication operator doesn’t work in the direct manipulation of a string:

# create the sample string
s1 = "alpharithms"

# attempt a direct multiplication operation
s2 = s1 * " is cool"

# output
TypeError: can't multiply sequence by non-int of type 'str'

# attempt an assignment operation
s1 *= " is cool"

# output
TypeError: can't multiply sequence by non-int of type 'str'

Python does allow the multiplication operator to be used to create multiple copies of a string. Consider the following example:

# Create an example string
s1 = "alpharithms"

# Use multiplication modifier with an integer value
# to create a new string made of duplicates of the
# initial string
s2 = s1 * 5

print(s2)
# output
alpharithmsalpharithmsalpharithmsalpharithmsalpharithms

The same output would be produced using the s1 *= 5 syntax. On a conceptual level this makes sense — equivalent to issuing the instruction “create 5 copies of s1“. What would happen if we used a fractional value though? Let’s see what happens when we try to create 5 and a half copies of the string:

# Create an example string
s1 = "alpharithms"

# Create 5 and a half copies
s2 = s1 * 5.5

TypeError: can't multiply sequence by non-int of type 'float'

Here we see a TypeError: can’t multiply sequence by non-int of type ‘float’ exception being raised. Python could 100% have elected to interpret fractional values such as floats to return a percentage of total characters with creating copies of strings. In this case the 0.5 would be 11/2 would be 5.5, rounded down to the nearest whole-number 5 characters: alpha. This is not the case however and float multiplication cannot be used with strings.

Example 3: Mixing Operators

It should be clear at this point that the addition and multiplication operators are useful for manipulating strings. We have seen the application of each in isolate but have not yet considered how one might use them in conjunction with one another. Consider the following code:

# create a sample string
s1 = "alpharithms"

# Create 5 copies separated by a space
s2 = s1 + " " * 5

# print result
print(s2)

# result
alpharithms

Rather than the expected 5 copies of alpharithms we instead see what looks to be a single copy! In fact, this is a single copy with 5 additional space characters appended to the end. If the " " portion was replaced with "-" the output would be alpharithms-----.

This example highlights that operator precedence is valid even when dealing with strings. To add the space between 5 copies as intended, we would need to add parenthesis to specify a different order of operations as such:

# create a sample string 
s1 = "alpharithms"

# Create 5 copies separated by a space 
s2 = s1 + " " * 5 

# print result 
print(s2) 

# result
alpharithms alpharithms alpharithms alpharithms alpharithms 

Here we see the output returned as expected. By adding the ( and ) characters around the s1 + " " operation we add the space character before creating 5 copies of the string!

Example 4: User Input Converts to Strings

When accepting user input in Python, any input provided by the user is converted into a string. For example, the following code prompts the user for a number that will be multiplied by the value 3:

# prompt user
value = input("Enter a number to multiply by 3: ")

# < enter the number 3 here >

# Multiply input by 3
result = value * 3

# Display result to user
print("The result is:", result)

# View result
The Result is: 333

Here we entered a value of 3 at the prompt and noticed a return value of 333 — clearly not an accurate calculation of 3 * 3 = 9. The issue is that python interprets the user inputted value of 3 as a string, which results in an operation equivalent to "3" * 3 which, as shown above, creates 3 copies of the string input.

This problem can be solved by converting user input that is expected to be numerical to numerical data before performing arithmetic operations. For example, the following code would result in the expected output:

# prompt user
value = input("Enter a number to multiply by 3: ")

# Multiply input by 3
result = int(value) * 3

# Display result to user
print("The result is:", result)

# Result
Enter a number to multiply by 3: 3
The result is: 9

Example x: Using Bytearry Objects to Manipulate Strings

Python creates new copies of any strings in which changing manipulations are made. As a broadly implying description — Python allocates new memory when strings are being mutated. As such, performing large numbers of string manipulations can become a burden on memory. To get around this issue, byte-arrays can be created as such:

# create a byte array from a string, encoded as ascii
s1 = bytearray("alpharithms", encoding='ascii')

# Change the last character to a newline
s1[-1:] = bytearray("\n", encoding='ascii')

# print decoded result
print(s1.decode('ascii'))

# Output
alpharithm

We have an entire article dedicated to the topic of using Python bytearry objects. Check it out to learn more about this built-in function of Python and how it relates to manipulating strings!

Final Thoughts

Python strings are just one of the many data types offered to developers. The decisions made during Python’s development prioritize syntactic ease vs. conceptual precedence such that somewhat odd syntaxes such as using the * operator to create copies of strings can be used. However alien compared to other popular programming languages this approach is without a doubt convenient.

Here we’ve seen how arithmetic operators can be used to manipulate Python strings. The most common error is when attempting to multiply via floating-point values or in creating copies rather than numerical values from user input. Keeping these in mind can help leverage the power of Python string manipulation syntax without generating a TypeError.

Zαck West
Full-Stack Software Engineer with 10+ years of experience. Expertise in developing distributed systems, implementing object-oriented models with a focus on semantic clarity, driving development with TDD, enhancing interfaces through thoughtful visual design, and developing deep learning agents.