The Secret Life of Python: The Shadow Name

Published: (February 3, 2026 at 09:44 PM EST)
3 min read
Source: Dev.to

Source: Dev.to

Understanding Variable Shadowing and Built‑ins

Timothy stared at his screen, his brow furrowed.

“Margaret? I think I actually broke Python this time.”

Margaret looked up from her tea.

“That is a bold claim, Timothy. What makes you say that?”

“It’s the list() function,” Timothy said, pointing to his monitor. “I’ve used it a thousand times to convert data. But suddenly Python is telling me it doesn’t work anymore. It says a list is ‘not callable’.”

The Problem in Code

# Timothy's script to process customer IDs

# Step 1: Create a list of current IDs
list = [101, 102, 103]
print(f"Current IDs: {list}")

# Step 2: Convert a tuple of new IDs into a list
new_ids_tuple = (201, 202, 203)
processed_ids = list(new_ids_tuple)  # “See?” Timothy argued. “I am trying to use `list()` to convert that tuple. But Python says the list object is not callable. Since when can I not call the list function?”

Margaret smiled gently. “Python is working perfectly, Timothy. The problem is that you borrowed its name tag.”

The LEGB Rule

Margaret wrote four letters on the whiteboard: L.E.G.B.

  • Local Scope – inside the current function
  • Enclosing Scope – nested functions
  • Global Scope – the main script
  • Built‑in Scope – Python’s core tools

“Names like list, str, print, and max live in the Built‑in Scope—the bottom of the toolbox.
Python allows you to create variables in the Global Scope. When you wrote list = [101, 102, 103], you placed a new label named list on top of the built‑in one.
So when the code reached Step 2 and you called list(new_ids_tuple), Python found your global variable first, stopped looking, and tried to call a list object, which isn’t callable.”

Variable Shadowing

Timothy sighed. “Why does Python even allow me to do that? Why not just forbid me from using the word list?”

“Because Python assumes you are a consenting adult,” Margaret replied. “Advanced users sometimes need to override built‑in behavior for testing or special frameworks. Python gives you the power to change anything—even if that means you occasionally trip over your own shoelaces.”

“So I just shadowed the tool with my own variable,” Timothy said.
“Exactly. This is called Variable Shadowing.”

Fixing the Issue

# Margaret's fix: descriptive naming

# Step 1: Use a descriptive name, not a reserved word
current_ids = [101, 102, 103]
print(f"Current IDs: {current_ids}")

# Step 2: Now `list` still refers to the built‑in function
new_ids_tuple = (201, 202, 203)
processed_ids = list(new_ids_tuple)  # Works perfectly!

print(f"Processed: {processed_ids}")

Output

Current IDs: [101, 102, 103]
Processed: [201, 202, 203]

“Much better,” Timothy said. “And current_ids actually tells me what the data is, rather than just what type it is.”

Common Traps

TrapSymptomCauseFix
Naming a variable list, str, dict, max, or idTypeError: 'list' object is not callable later in the scriptShadowing – the variable overwrites the built‑in reference (LEGB)Rename the variable to something descriptive
Bad examplesstr = "Hello"
max = 10
Same shadowing issuegreeting = "Hello"
max_score = 10

Quick check: If your variable name turns a special color in your code editor (often purple or blue), consider renaming it to avoid colliding with a built‑in.

Timothy made a note.

“I feel bad for blaming Python now. It was doing exactly what I told it to do.”

Margaret smiled.

“It usually is. That is both its greatest strength and its greatest frustration.”

Stay tuned for the next episode, where Timothy learns why comparing a string "5" to the number 5 can fail silently or crash in certain contexts.

Back to Blog

Related posts

Read more »

Python Closures: Coming from JavaScript

Learning with Books vs. Videos > “Books – Gain depth of knowledge on a topic > Videos – Quickly ramp up to use a specific technology” I still reach for a book...