Get AI summaries of any video or article — Sign up free
5 Common Python Mistakes and How to Fix Them thumbnail

5 Common Python Mistakes and How to Fix Them

Corey Schafer·
5 min read

Based on Corey Schafer's video on YouTube. If you like this content, support the original creators by watching, liking and subscribing to their content.

TL;DR

Configure your editor/IDE to translate tabs to spaces to prevent indentation errors that appear correct visually.

Briefing

Python’s most common “mystery errors” often come down to a handful of avoidable habits: inconsistent indentation, naming conflicts, mutable defaults, iterator exhaustion, and wildcard imports. Fixing these issues early prevents time-wasting debugging—especially when code looks correct at a glance but fails at runtime.

The first pitfall is mixing tabs and spaces, which triggers indentation errors like “IndentationError: unindent does not match any outer indentation level.” The transcript shows how a program can appear aligned in a text editor while Python still treats the indentation levels as mismatched. The practical fix is to use an editor or IDE setting that automatically translates tabs to spaces (the example uses Sublime Text’s “translate tabs to spaces” setting). For extra safety, a linter such as pylint can catch problems that are easy to miss visually.

Next comes a naming conflict that breaks imports in a way that can be confusing: creating a local module with the same name as a standard-library module. The example creates a file named math.py (and then uses “from math import radians” and “sine”), but Python prioritizes the local module over the standard library. The result is an import error (“cannot import name radians for math”). Renaming the local file (e.g., to project_PI) restores the intended import from the real standard-library math module. The same issue can happen with third-party packages like Flask or Django if a local file or package shadows those names.

A related mistake involves variable shadowing. If a variable is named the same as an imported function—such as assigning radians = radians(90 degrees)—the function reference gets overwritten by a float value. Later, calling radians(45 degrees) fails with “float object is not callable.” The fix is simple: avoid reusing imported function names for variables (use a different variable name like rads or rad_90).

Mutable default arguments are another classic trap. Default parameter values are evaluated once when the function is defined, not each time it’s called. The transcript demonstrates a function add_employee(employee, employee_list=[]) where repeated calls without passing employee_list keep appending to the same list instance. The remedy is to use employee_list=None and create a new list inside the function when the argument is None. The same principle applies to other defaults like date/time.now: if it’s set as a default value, it won’t update across calls.

Iterator exhaustion explains a common Python 2 vs Python 3 surprise. In Python 3, zip returns an iterator rather than a fully materialized list. Converting that iterator to a list consumes it; attempting to iterate over it again yields no results. The fix is to convert zip to a list once and then iterate over that list, or otherwise avoid reusing an exhausted iterator.

Finally, wildcard imports (from module import *) make code harder to debug and can silently overwrite names. The transcript shows how importing * from multiple modules can cause one function (like escape) to replace another, leading to confusing behavior. The recommended approach is explicit imports—either import the module and use module.function, or import specific names directly—so it’s always clear where each symbol comes from.

Cornell Notes

The transcript identifies five recurring Python mistakes that lead to confusing runtime errors: mixed tabs/spaces, import shadowing, variable shadowing, mutable default arguments, and iterator exhaustion—plus a related bad practice with wildcard imports. Indentation errors happen when editors insert different whitespace types; fix it by configuring the editor to translate tabs to spaces and using tools like pylint. Import and variable shadowing occur when local files or variables reuse names from standard-library or imported functions, breaking expected references. Mutable defaults (like []) are evaluated once, so repeated calls reuse the same object; use None and create a new list inside the function. In Python 3, zip is an iterator that gets exhausted when consumed, so materialize it once if it must be reused.

Why does mixing tabs and spaces cause errors even when code “looks” aligned?

Python treats indentation levels as specific whitespace counts. When tabs and spaces are mixed inconsistently, the interpreter may see different indentation widths than the editor displays, producing errors such as “IndentationError: unindent does not match any outer indentation level.” A reliable fix is to configure the editor/IDE to translate tabs to spaces automatically (the transcript uses Sublime Text’s translate tabs to spaces setting) and to use a linter like pylint to catch indentation-related issues that aren’t obvious visually.

How can naming a local file break standard-library imports?

Python’s import resolution prefers local modules over standard-library modules when names collide. The transcript demonstrates creating math.py in the current directory and then running “from math import radians.” Instead of importing the standard-library math module, Python imports the local math.py, leading to an error like “cannot import name radians for math.” Renaming the local module (e.g., to project_PI) removes the conflict.

What does variable shadowing do to imported functions?

If a variable assignment reuses the same name as an imported function, the function reference gets overwritten. The transcript imports radians from math, then assigns radians = radians(90 degrees), turning radians into a float. Later, calling radians(45 degrees) fails with “float object is not callable” because the code is trying to call a float. Renaming the variable (e.g., rads or rad_90) prevents the overwrite.

Why do mutable default arguments behave unexpectedly across function calls?

Default argument expressions are evaluated once when the function is defined, not each time the function runs. With a default like employee_list=[], repeated calls without passing employee_list reuse the same list object and keep appending. The transcript fixes this by using employee_list=None and creating a new list inside the function when employee_list is None. The same logic explains why defaults like date/time.now won’t update per call unless computed inside the function.

What does “iterator exhaustion” mean for zip in Python 3?

In Python 3, zip returns an iterator. Iterators can be consumed only once. The transcript shows converting zip to a list (which consumes the iterator) and then trying to iterate over the same zip object again—resulting in no output because the iterator is exhausted. The fix is to convert zip to a list once and then iterate over that list, or otherwise avoid reusing the exhausted iterator.

Why are wildcard imports (from X import *) risky?

Wildcard imports obscure where names come from, making debugging harder. They also increase the chance of name collisions: importing * from multiple modules can overwrite functions with the same name. The transcript illustrates this with escape functions from HTML and glob, where the later import wins and changes what escape refers to. Prefer explicit imports (import the module and use module.name, or import specific names) to keep symbol origins clear and avoid silent overwrites.

Review Questions

  1. What specific mechanism causes mutable default arguments like [] to persist across calls, and how does using None change the behavior?
  2. In Python 3, what happens when you convert a zip iterator to a list and then try to iterate over the original zip object again?
  3. How do import shadowing and variable shadowing differ, and what symptoms would each produce at runtime?

Key Points

  1. 1

    Configure your editor/IDE to translate tabs to spaces to prevent indentation errors that appear correct visually.

  2. 2

    Avoid naming local modules or packages the same as standard-library modules or third-party packages you intend to import.

  3. 3

    Do not reuse imported function names for variables; shadowing can turn callables into non-callable values and trigger runtime errors.

  4. 4

    Replace mutable default arguments (like []) with None and create new objects inside the function.

  5. 5

    Compute time-dependent defaults (like date/time.now) inside the function rather than as default parameter values.

  6. 6

    Treat Python 3 zip as an iterator: materialize it once (e.g., list(zip(...))) if you need to iterate multiple times.

  7. 7

    Use explicit imports instead of wildcard imports to prevent hidden name origins and accidental overwrites.

Highlights

Mixed tabs and spaces can produce indentation errors even when an editor shows the code as properly aligned; translating tabs to spaces fixes it.
A local file named math.py can break “from math import radians” because Python imports the local module first, not the standard library.
Mutable defaults are evaluated once at function definition time, so employee_list=[] can keep growing across calls unless replaced with None.
In Python 3, zip returns an iterator; converting it to a list exhausts it, so re-iterating the same zip object yields nothing.
Wildcard imports can silently overwrite same-named functions from different modules, making behavior unpredictable and debugging harder.

Topics

  • Indentation Errors
  • Import Shadowing
  • Mutable Default Arguments
  • Iterator Exhaustion
  • Wildcard Imports

Mentioned