Skip to content

Common Python Pitfalls for Beginners: Tips to Avoid Them

Published: at 02:00 AM

Python is an incredibly versatile, user-friendly programming language that is a great choice for beginners. However, there are some common mistakes and challenges that new Python learners often encounter. Being aware of these potential pitfalls can help you anticipate and avoid them in your own learning journey. This guide examines some of the most prevalent pitfalls for Python beginners and provides tips to steer clear of them.

Table of Contents

Open Table of Contents

Importing Modules

One of the first things beginners learn in Python is how to import modules to access additional functionality beyond the standard library. However, it is easy to run into issues if you do not fully understand Python’s module system.

Forgetting to Import a Module

Python will raise an ImportError if you try to use a module that has not been imported. For example:

# WILL RAISE AN IMPORT ERROR
print(math.pi)

Always make sure to import any external modules at the start of your code before trying to use them:

import math

print(math.pi) # Imports math module to access constants like pi

You can also import specific attributes or functions directly:

from math import pi
print(pi)

Importing Multiple Times

There is no need to import the same module multiple times. The module will be cached after the first import, so subsequent imports are redundant.

# Redundant to import math twice
import math
import math

Using from module import *

While convenient, importing all names from a module using the * wildcard is considered bad practice, as it pollutes your namespace and could overwrite existing names without warning.

# Avoid - pollutes namespace
from math import *

Import only what you need directly:

# Better practice
from math import pi, sqrt

Forgetting to Import Submodules

When importing from a package, you need to explicitly import submodules as well. For example, import numpy does not import numpy.random - you need to import it separately:

import numpy # Imports base numpy module

import numpy.random # Must also import numpy submodules

Pay close attention to import statements to avoid errors. Always fully qualify submodule names.

Indentation and Whitespace

Unlike other languages, Python uses whitespace indentation to delineate blocks of code instead of braces or keywords. Not indenting code properly is a huge source of errors for Python beginners.

Forgetting to Indent Within Blocks

All lines within a code block must share the same indentation level, usually 4 spaces. Forgetting to indent will raise an IndentationError:

# ERROR - 'print' not indented properly
if x > 0:
print(x)
# Fixed with consistent indentation
if x > 0:
    print(x)

It is recommended to always use spaces, not tabs, for indentation in Python as per style guides like PEP 8. Configure your editor to insert spaces for consistency.

Indent consistently after every colon (:) when starting a new block.

Unintentional Whitespace

Extra whitespace such as trailing spaces or inconsistent indentation can also break Python code or cause logical errors that are tough to debug.

# Whitespace before print breaks code
if x > 0:
        print(x)

Carefully check all indentation levels and remove extraneous whitespace in your code. Most text editors have a “show invisibles” setting that highlights whitespace and indentation. Using a PEP 8 linter also helps enforce proper styling.

Mixing Spaces and Tabs

Python disallows mixing spaces and tabs for indentation. Stick to using only spaces or only tabs consistently.

Unclosed Blocks

Forgetting to close a code block with the appropriate indentation will cause an error:

# Error - for loop not closed properly
for i in range(5):
print(i)

x = 10

Properly indent the end of a code block to align with the start of the block:

# Fixed - for loop closed correctly
for i in range(5):
    print(i)

x = 10

Pay close attention to indentation and whitespace to avoid frustrating syntax errors. Use linters and formatting tools to help catch inconsistencies.

Missing Parentheses, Brackets, Braces

Python syntax relies heavily on correct use of parentheses, brackets, and braces for function calls, containers, and blocks. Omitting a single parenthesis or bracket can break code.

Forgetting Closing Parentheses on Functions

Parentheses are required to call functions in Python. Forgetting a closing parenthesis will raise a SyntaxError:

# Error - missing closing parenthesis
print('Hello world'

print('Hello world') # Works

Forgetting Commas in Lists and Tuples

Items in Python lists, tuples, and other containers must be separated by commas. Omitting a comma can raise errors:

# Error - missing comma
nums = [1 2 3]

nums = [1, 2, 3] # Works

Always double check commas when creating collections in Python.

Unbalanced Braces

Braces must come in matching pairs in Python. Unbalanced braces will break code. Python will often clearly indicate the line where it encountered the unbalanced brace in the error message:

# Syntax error due to mismatched braces
if (x > 0):
  print(x)
} # Unbalanced brace - Python points to this line

Take care to properly close all opened braces, brackets, and parentheses in your Python code.

Wrong Comparator or Boolean Operator

Python has extremely strict rules around which operators can be used for comparisons and Boolean logic. Using the wrong operator will raise an exception.

Assignment (=) Instead of Equality (==)

The assignment operator (=) is not interchangeable with the equality operator (==) for comparing values.

# Sets x equal to 10 instead of comparing
if x = 10:
  print('x is 10')

Use == to check for equality:

# Checks if x equals 10
if x == 10:
  print('x is 10')

is vs == for Comparing Objects

Unlike ==, which checks if values are equivalent, is evaluates if two objects are identical in memory. Beginners often mix up == and is when comparing objects:

a = [1, 2, 3]
b = a

print(a == b) # True, values are equal

print(a is b) # Also true, a and b reference the same list object

Using Logical Operator Instead of Boolean Operators

Python does not allow using logical operators like and/or in place of bitwise Boolean operators like &/| in circumstances that expect a boolean result.

For example:

# Evaluates to 2 instead of False
x = 1 and 2

# Use & for boolean result
x = 1 & 2 # x is False

Mutable vs Immutable Types

Python primitive types like integers, strings, and tuples are immutable. Changing them actually creates a new object. This trips up many beginners trying to modify literals directly.

Trying to Modify a String

Strings cannot be directly modified in Python as they are immutable. However, you can create a new string by concatenating slices:

s = 'hello'
s[0] = 'H' # Error! Can't modify string directly

s = 'H' + s[1:] # 'Hello'

Trying to Modify a Tuple

Like strings, tuples cannot be changed once created. Trying to modify a tuple raises an error:

# Tuples are immutable
nums = (1, 2, 3)

nums[0] = 4 # Error

If you need a mutable collection, use a list instead of a tuple.

Assuming List Operations Don’t Return New Objects

When modifying lists in place, remember that operations like append()/sort() modify the existing list rather than returning a new list object. This catches some beginners off guard:

a = [1, 2, 3]
b = a

a.append(4)

print(b) # Surprisingly prints [1, 2, 3, 4]

However, some list methods like sorted() return a new list:

a = [3, 1, 2]
b = sorted(a) # Returns new sorted list, doesn't modify a

b references the same mutable list as a, so in-place changes to a are reflected in b.

Problems with Main Guard and Scope

Python scripts designed to be run as executables should use a main guard to control flow when imported from another module. Beginners often forget to add a main guard or misunderstand scope.

Forgetting Main Guard

When imported, scripts without a if __name__ == '__main__' guard will run automatically, which is usually not the desired behavior.

Add a main guard to control executed code:

# Without guard
print('Code runs automatically when imported!')

# With guard - only executes when run directly
if __name__ == '__main__':
    print('Code only runs when executed directly')

Accessing Variables Out of Scope

Python scope works on a local/global/builtin level. Trying to access variables outside the current scope raises an error:

def foo():
  y = 10 # Local variable

  print(x) # Error - unknown variable x

x = 5 # Global scope
foo()

Carefully manage variable scope to avoid issues. Declare global variables at the start of scripts when necessary, but do so sparingly as globals can lead to hard-to-debug errors in larger programs.

Misusing Class and Instance Attributes

Python beginners often mix up class, instance, and static attributes when first using object-oriented features.

Accessing Uninitialized Instance Attributes

Instance attributes must be initialized before being referenced. Accessing non-existent attributes raises an AttributeError:

class Person:
  pass

p = Person()
print(p.name) # Error - 'Person' object has no attribute 'name'

Initialize attributes inside __init__() or through dot notation access:

class Person:
  def __init__(self):
    self.name = 'John' # Initialize instance attribute

p = Person()
print(p.name) # Prints 'John'

Modifying Class Attributes on Instances

Modifying a class attribute on an instance actually creates a new instance attribute, leaving the original class attribute unchanged:

class Person:
  species = 'Human' # Class attribute

p = Person()
p.species = 'Alien' # Creates new instance attribute

print(Person.species) # Unchanged - still prints 'Human'

Modify class attributes directly on the class itself:

Person.species = 'Alien'

Forgetting self Argument

Within class methods, self provides access to the current instance. Omitting self will raise an error:

class Person:
  def display_name(name): # Incorrect - missing self
    print(name)

p = Person()
p.display_name('John') # Raises TypeError

Include self to access instance attributes:

class Person:
  def display_name(self, name):
    print(self.name) # self allows accessing name attribute

p = Person()
p.name = 'John'
p.display_name() # Prints 'John'

Pay close attention to instance vs class attributes, along with self usage, to properly leverage classes.

Summary

Learning common pitfalls will help you avoid many frustrating bugs when starting out with Python. Pay close attention to the examples and guidelines provided here to steer clear of issues in your own code. With practice, you will gain experience and familiarity with Python’s syntax and conventions needed to write clean, robust code.