Importing variables non-deterministic?

Steven D'Aprano steve+comp.lang.python at pearwood.info
Sat Aug 17 11:01:41 EDT 2013


On Sat, 17 Aug 2013 07:25:43 -0700, tmellman wrote:

> I have this file that has this:
> 
>     from struct_global import y
>     from struct_global import x

The import of x appears to be irrelevant, so I'll ignore it.

Here you import y from the struct_global module. This creates a new name 
y in the current module. y is bound to the same object that 
struct_global.y happens to be at the moment of the import, but y is *not* 
a reference to the *name* struct_global.y.

This means that the two names, "y in current module" and "y in 
struct_global module" point to the same object, but they aren't two 
aliases for the same variable. They are different variables that just 
happen to share the same value (an object).

If the object mutates (which ints cannot do), then both "y"s will see the 
change (naturally, since both refer to the same object). But if either 
name is rebound to a different object, the other name is unaffected.

We can see the same behaviour locally, without an import, by doing this:

py> x = [1]
py> y = x  # y is bound to the same object as x
py> print(y)
[1]
py> x.append(2)  # mutate x in place
py> print(y)
[1, 2]
py> x = [1, 2, 3]  # re-bind x to a new object
py> print(y)  # y still bound to the first object
[1, 2]


"from struct_globals import y" is a binding operation, no different from 
"y = something".


>   and this usage (a few lines later in a class method definition in the
>   same file):
> 
>         if y == x:
> 
>   If I stop there in pdb, I can observe this:
> 
>     (Pdb) p x
>     66
>     (Pdb) p y
>     -1
>     (Pdb) from struct_global import y
>     (Pdb) p y
>     62

And here you re-import the name "y" from struct_global. That rebinds the 
current module's "y" with whatever value struct_global.y has *now*, 
rather than a second (or a minute, or an hour) earlier when the first 
import took place. Obviously at some point between the first import and 
the second import, struct_global.y must have been reassigned from -1 to 
62.

This goes to show why global variables are considered harmful, and why 
clean, modern program design tries to reduce the use of them as much as 
possible. Global variables are too easily modified by, well, *anything*. 
The sort of behaviour you are seeing is sometimes called "action at a 
distance" -- something, anything, anywhere in your program, possibly 
buried deep, deep down inside some function you might never suspect, is 
changing the global variable.


> How did my first import get hidden?

You reassigned to it. "from struct_global import y" is practically 
syntactic sugar for this:

import struct_global
y = struct_global.y


> Is there any way to see where a
> variable resolves to?

You just did. You inspected the variable "y", and you saw that it is 
assigned the value 62.


-- 
Steven



More information about the Python-list mailing list