Surprising difference in behavior between "import blah" and "from blah import thing"

J. Cliff Dyer jcd at sdf.lonestar.org
Thu May 8 16:36:44 EDT 2008


On Thu, 2008-05-08 at 12:00 -0700, Eric Hanchrow wrote:
> (This is with Python 2.5.2, on Ubuntu Hardy, if it matters.)
> 
> This seems so basic that I'm surprised that I didn't find anything
> about it in the FAQ.  (Yes, I am fairly new to Python.)
> 
> Here are three tiny files:
> 
> ==== mut.py ====
> 
>     import system
>     from system import thing
> 
>     def doit():
>         print "       thing is", thing
> 
>     def do_it_slightly_differently():
>         print "system.thing is", system.thing
> 
> ==== system.py ====
>     thing = "I am the original thing!!"
> 
> ==== test.py ====
>     import mut
>     mut.doit()
>     mut.do_it_slightly_differently()
>     import system
> 
>     system.thing = "The new improved thing"
>     mut.doit()
>     mut.do_it_slightly_differently()
> 
> When I run "python test.py", I see
> 
>            thing is I am the original thing!!
>     system.thing is I am the original thing!!
>            thing is I am the original thing!!
>     system.thing is The new improved thing
> 
> What surprises me is that the assignment to "system.thing" in test.py
> only seems to affect the use of "system.thing" in mut.py, and not
> affect the use of just plain "thing" in that same file.  I would have
> expected my assignment to have affected both, or perhaps neither.
> 
> I have no idea why these two differ.  Can someone explain?

It's the same reason as this:

>>> x=5
>>> y=x
>>> x
5
>>> y
5
>>> x=6
>>> x
6
>>> y
5
>>> 

Python "variables" are just names that point at objects.  When you
import, the imported module gets bound to a name.  When you use the an
assignment statement, you bind a new object to the name, but other names
bound to the object are not affected.  

So in your code, when you say 

>>> system.thing = "The new improved thing"

You rebind the name system.thing, but the object it was originally bound
to is unaffected.  Strings are immutable, so you couldn't change that
object if you tried.  thing is still bound to the original object.
Another feature of this behavior is as follows:
>>> x=5
>>> x is y
True
>>> x=5
>>> y=x
>>> x is y
True
>>> x=6
>>> x is y
False
>>> 

The "is" operator tells you that the two objects are the same object.
When you reassign one, it no longer points to the same object as the
other.  You would get the same behaviour in your code comparing
system.thing and thing.

Cheers,
Cliff





More information about the Python-list mailing list