__bases__ misleading error message

Steven D'Aprano steve+comp.lang.python at pearwood.info
Sun Jan 25 04:18:01 CET 2015

Mario Figueiredo wrote:

> But that begs the OT question: How does Python maps names to memory
> addresses in the interpreter?

It doesn't.

You are thinking of an execution model like C or Pascal, where variables are
best thought of as fixed memory addresses. But Python, like many modern
languages (Java, Ruby, Lua, ...) uses a name-binding model.

Semantically, the fixed memory address model means that each variable is
like a fixed-width bucket, where the size depends on the type. That's why
the compiler needs to associate a fixed type with each variable, so it
knows how much space to allocate and how to initialise the bytes:

m = [0000]
n = [0000]
x = [8FFFFFFF]

Assigning a value to a variable ("m = 42", hex 2A) results in the compiler
storing that value in the bucket; assignment makes a copy: "n = m" leads to
two independent buckets with the same value:

m = [002A]
n = [002A]

Values and variables are dependent on each other. You can't have a variable
with no value, and you can't have a value with no variable. (This is an
over-simplification, but mostly true.)

The name-binding model is different. Values (objects) and names are
independent. Values can exist even if they have no name (although the
garbage collector will delete them as soon as they are unused). The
compiler associates a name to a value. One good mental model is to think of
the compiler attaching a piece of string from the name to its associated
object. Assigning n = m means that both names end up tied to the same
object, and there can be objects with no associated name. (So long as
*something* refers to them, the garbage collector will leave them be.)

m -----------------+----------- 0x2A
n ----------------/
x ----------------------------- 1.2345
s -----\                        "Hello world"
        +---------------------- "Goodbye now"

Under the hood, this is usually implemented using pointers. If you are
familiar with pointer semantics, you might think of these pieces of string
as pointers, except that you cannot do pointer arithmetic on them. But that
is merely the *implementation* of the language's variable model.

In Python, global variables use a dict, and there is a function to retrieve
that dict:

py> d = globals()
py> d['x'] = 23  # don't do this!
py> x

It's not *wrong* or forbidden to write to globals this way. It's just

>     "__main__"
>     from module import a_name
>     y = a_name + 1
> How does python interpreter know how to map 'name' to the correct memory
> location, if this __main__ code is only ran after 'module' code?

When the statement `from module import a_name` executes, Python:

(1) imports module;
(2) looks up "a_name" in module's namespace (a dict);
(3) creates an entry "a_name" in the current namespace (assuming 
    one doesn't already exist);
(4) and binds it to the object found in Step 2.

When it executes `y = a_name + 1`, Python:

(1) looks up the name "a_name" in the current namespace;
(2) creates the anonymous object 1, unbound to any name;
(3) calls + with those two objects;
(4) which (assuming it succeeds) creates a new object;
(5) creates an entry "y" in the current namespace;
(6) and binds it to the object returned in Step 4.


More information about the Python-list mailing list