4 Simple Ways to Refactor Your Python Code

Learn new techniques and optimize your existing code

4 Simple Ways to Refactor Your Python Code
Photo by calvin chou on Unsplash

Refactoring is the process of updating existing code while functionally remain the same. There are a variety of reasons for refactoring code including performance, readability, and future scalability.

Refactoring is an important part of any coder’s process, not just advanced developers. For the less experienced audience, refactoring code is an excellent opportunity to learn and practice new techniques. Level up from get it done to get it done correctly!

We’ll go over five easy ways to refactor your beginner Python code, explaining the benefits of each and showing before and after code.

Define Functions for Repetitive Tasks

The first and probably most important refactoring we can do is defining functions for repetitive tasks. A function is a defined set of statements that can be executed by using the function’s name — known as a function call.

Functions provide a multitude of benefits, but from the perspective of refactoring, we will reduce the size of our code, improving readability. Additionally, when we need to update the task, it only has to happen in one place — the function’s definition.

Let’s take a look at an example where we need to request both a length and width of a rectangle to calculate the area.

Beforewhile True:
 length = int(input("Enter the length: "))
 if length > 0:
   breakwhile True:
 width = int(input("Enter the width: "))
 if length > 0:
   breakprint("The area is", length * width)

Notice how the two blocks look nearly identical. What if we’re calculating the volume of a cube? Most likely we’d copy/paste the while loop, changing the variable name and input prompt. Let’s refactor this using a function.

Refactoreddef input_positive_integer(prompt):
 while True:
   input_value = int(input(prompt))
   if input_value > 0:
     return input_valuelength = input_positive_integer("Enter the length: ")
width = input_positive_integer("Enter the width: ")
print("The area is", length * width)

Now our code is easier to read and we begin to save some lines of code. What’s even better is that in the future we can take our function and easily insert it into another script, saving us time.

List Comprehensions Instead of For Loops

List comprehensions are one of the most iconic Python constructs. List comprehensions are a cleaner, faster implementation relative to many simple for loops.

A Beginner’s Guide to Python List Comprehensions
Eliminate 90% of your for loops

There are many benefits of refactoring for loops into list comprehensions: the code will run faster, existing data is not mutated, and list comprehensions are easier to read at a glance once you get used to them.

Let’s take a look at two examples, one simple and one a bit more complicated.

In our first example, we’re going to keep the odd numbers from a list of integers.

Beforemy_numbers = [1,2,3,4,5]
odd_numbers = []
for item in my_numbers:
 if item % 2 == 1:
   odd_numbers.append(item)print(odd_numbers) # [1, 3, 5]

In this example, we loop through my_numbers and use the remainder operator to determine if we insert the item into odd_numbers.

Refactoredmy_numbers = [1,2,3,4,5]
odd_numbers = [item for item in my_numbers if item % 2 == 1]

To summarize this refactoring: the list comprehension is an assignment into odd_numbers, we iterate over my_numbers, we set the return (the first item), and we’re able to apply an if-statement to filter.


We can build more complex list comprehensions, resulting in even greater benefits. For the second example, let’s assume we have a two-dimensional matrix of integers and we want to square each value.

Beforematrix = [[1,2,3],[4,5,6],[7,8,9]]
squared_matrix = []for row in matrix:
 line = []
 for item in row:
   line.append(item ** 2)
 squared_matrix.append(line)print(squared_matrix)
# [[1, 4, 9], [16, 25, 36], [49, 64, 81]]

We have to use a nested for loop along with a temporary variable to hold each line before insertion into our final variable.

Refactoredmatrix = [[1,2,3],[4,5,6],[7,8,9]]
squared_matrix = [
 [
   item ** 2
   for item in row
 ]
 for row in matrix
]print(squared_matrix)
# [[1, 4, 9], [16, 25, 36], [49, 64, 81]]

We’ve spaced out the comprehension for readability, but the entire nested for loop and calculation is handled within a single assignment.

The Logical OR Operator Instead of Ternary Operator

Assigning one of two values can be handled with a simple if-statement such as this:if args['website']:
 website = args['website']
else:
 website = "https://medium.com/@jhsu98"

These types of “either-or” assignments are traditionally able to be performed with the ternary operator, which consolidates the assignment into a single statement.

Beforewebsite = args['website'] if args['website'] else "https://medium.com/@jhsu98"

The structure of the ternary operator is as follows:

value if true | expression | value if false

When the expression is to evaluate if the “value-if-true” coerces into a True boolean value, then the logical OR operator can simplify the arguably difficult-to-read ternary operator.

Refactoredwebsite = args['website'] or "https://medium.com/@jhsu98"

The logical OR operator works by attempting to assign the first value. In the event that the first value coerces to a boolean False—None, empty variable, etc.—then the second value will be used.

This refactoring is much easier to read and effectively allows us to set a default value during a variable assignment.

The enumerate() Function Instead of range()

Especially if you are coming from another programming language, Python for loops may be confusing. Your initial instinct may be to create an index variable and use that to iterate over your list.

As a result, the range() function is often discovered and used. This practice is not considered “Pythonic” being against the recommended style guide and best practices.

Stop Using range() in Your Python for Loops
How to access the current index using the enumerate() function

If you absolutely need the index of each list value, then we can use the enumerate() function instead to still iterate over the actual list rather than using an independent variable as an index proxy.

Beforeraces = ["Terran", "Protoss", "Zerg"]
for i in range(len(races)):
 print(i+1, races[i])# 1 Terran
# 2 Protoss
# 3 Zerg

Using the index on the original list leads to bad practices such as updating original values and also becomes difficult to read…especially in complex nested data structures. Also, we have to manually manipulate the index to shift the values into “counting numbers”.

Refactoredraces = ["Terran", "Protoss", "Zerg"]
for i, race in enumerate(races, 1):
 print(i, race)# 1 Terran
# 2 Protoss
# 3 Zerg

The enumerate() function takes two arguments, the iterable and the starting count value, and returns the current counter value and item in the iterable. Note: the temp count variable goes first in our for loop and the initial count value goes second in the function call, this is a common mistake.


Get in the habit of revisiting your code and attempting to refactor sections. Your development will be slower without the actual practice and execution of using optimized programming practices.

Thanks for reading. Please post your experiences, questions, and feedback below!

Subscribe to Dreams of Fortunes and Cookies

Sign up now to get access to the library of members-only issues.
Jamie Larson
Subscribe