This article assumes you’re already comfortable writing simple Python programs and know the basic syntax (if, for, functions, lists, etc.). We’re not learning how to use Python here—we’re learning why it works the way it does.

Over the last few articles, we’ve repeated the same idea several times.

A name starts referring to an object.

For example:

x = 10

or

numbers = [1, 2, 3]

We already know that a variable isn’t a “memory cell” containing a value.

Python creates an object.

Then a name starts referring to that object.

But this raises a new question.

Where is the name itself stored?


Try running this code.

name = "Python"

print(name)

Why does Python know what name is?

After all, we never explicitly told it:

“Store this variable over here.”

That means there must be some place where Python keeps track of all the names it knows about.

Such a place really does exist.

It’s called a namespace.


You can think of a namespace as a simple table.

The left column contains names.

The right column contains references to objects.

For example, after executing this code:

x = 10
text = "Hello"
numbers = [1, 2, 3]

the namespace might look like this:

Name         Object
----------------------------
x        ───► 10
text     ───► "Hello"
numbers  ───► [1, 2, 3]

Notice something important.

The table does not contain the objects themselves.

It only contains references to them.

That’s why multiple names can refer to the same object.

For example:

a = [1, 2]
b = a

Now the table looks like this:

Name     Object
-------------------------
a    ─┐
      ├────► [1, 2]
b    ─┘

We’ve already seen this situation before.

Now we can finally see where Python stores that information.


What happens when we execute an assignment like this?

x = 20

Python doesn’t go looking for some special “variable.”

Instead, it simply updates the entry in the namespace.

If the table originally looked like this:

x ───► 10

after the assignment it becomes:

x ───► 20

This is exactly why we’ve been saying that assignments change the reference, not the name itself.


Now let’s revisit the del statement.

What happens here?

del x

We already know the answer.

The object may continue to exist.

It isn’t deleted.

Instead, Python removes the entry from the namespace.

Before:

x ───► 10

After:

(no entry)

At that point, Python no longer knows about any name called x.

That’s why writing

print(x)

raises a NameError.

Not because the object disappeared.

But because the namespace no longer contains the name.


This leads to another interesting question.

If a namespace is just a table of names, how many namespaces are there?

Is there one namespace for the entire program?

Or are there several?

It turns out that Python has many namespaces.

For example, variables inside a function don’t get mixed together with variables defined outside the function.

That means Python creates separate namespaces for different parts of your program.

That’s why this code works:

x = 10

def func():
    x = 20
    print(x)

func()

print(x)

The output is:

20
10

Even though the name x appears twice.

Why?

Because these are two different entries in two different namespaces.


Namespaces are what allow Python to reuse the same names in different parts of a program without causing confusion.

For now, it’s enough to remember one simple idea.

A name never exists on its own.

It always belongs to a namespace.

That’s where Python stores the relationship between names and objects.


In the next article, we’ll take another step forward.

We now know that Python has multiple namespaces.

But how does Python decide which one to search?

Why does it find a local variable before a global one?

And what happens if the same name exists in several different namespaces?

That’s exactly what we’ll explore next.