Why do directly imported variables behave differently than those attached to imported module?

Chris Rebert clp2 at rebertia.com
Tue May 3 12:57:53 EDT 2011


On Tue, May 3, 2011 at 9:31 AM, Dun Peal <dunpealer at gmail.com> wrote:
> Hi!
>
> Here's the demonstrating code:
>
>    # module foo.py
>    var = 0
>
>    def set():
>        global var
>        var = 1
>
> Script using this module:
>
>    import foo
>    from foo import *
>
>    print var, foo.var
>    set()
>    print var, foo.var
>
> Script output:
>
>    0 0
>    0 1
>
> Apparently, the `var` we imported from `foo` never got set, but
> `foo.var` on the imported `foo` - did. Why?

Because imports (and assignments generally) bind names to values, they
don't alias names to other names.

from foo import *

can be thought of as essentially doing:

import foo
set = foo.set
var = foo.var
del foo

So the new, separate name __main__.var gets the current value of
foo.var at import-time, which is the integer 0.
You then call foo.set(), which re-binds foo.var to a new value (i.e.
1) rather than mutating the existing value (which would be impossible
anyway since integers are immutable). This has absolutely no effect on
__main__.var, which is an entirely separate binding.

The behavior is comparable to that of function arguments. Values can
be mutated, but re-binding names has only local effect:
>>> a = 0
>>> def incr(b):
...     b = 1 # rebinds local name b
...
>>> incr(a)
>>> a # outside name unaffected, just like in your example
0
>>> c = [7]
>>> def mutate_then_rebind(b):
...     b.append(99) # mutates passed-in value
...     b = [42] # rebinds local name; has no outside effect
...
>>> mutate_then_rebind(c)
>>> c # name still references same obj, but that obj has been mutated
[7, 99]

Cheers,
Chris
--
http://rebertia.com



More information about the Python-list mailing list