Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.lang.python > #4548 > unrolled thread

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

Started byDun Peal <dunpealer@gmail.com>
First post2011-05-03 09:31 -0700
Last post2011-05-03 15:11 -0700
Articles 12 — 8 participants

Back to article view | Back to comp.lang.python


Contents

  Why do directly imported variables behave differently than those attached to imported module? Dun Peal <dunpealer@gmail.com> - 2011-05-03 09:31 -0700
    Re: Why do directly imported variables behave differently than those attached to imported module? Chris Rebert <clp2@rebertia.com> - 2011-05-03 09:57 -0700
    Re: Why do directly imported variables behave differently than those attached to imported module? Daniel Kluev <dan.kluev@gmail.com> - 2011-05-04 03:57 +1100
    Re: Why do directly imported variables behave differently than those attached to imported module? Mel <mwilson@the-wire.com> - 2011-05-03 13:00 -0400
    Re: Why do directly imported variables behave differently than those attached to imported module? Terry Reedy <tjreedy@udel.edu> - 2011-05-03 13:13 -0400
    Re: Why do directly imported variables behave differently than those attached to imported module? harrismh777 <harrismh777@charter.net> - 2011-05-03 12:24 -0500
      Re: Why do directly imported variables behave differently than those attached to imported module? Dun Peal <dunpealer@gmail.com> - 2011-05-03 11:51 -0700
        Re: Why do directly imported variables behave differently than those attached to imported module? Dun Peal <dunpealer@gmail.com> - 2011-05-03 12:23 -0700
          Re: Why do directly imported variables behave differently than those attached to imported module? Daniel Kluev <dan.kluev@gmail.com> - 2011-05-04 06:55 +1100
    Re: Why do directly imported variables behave differently than those attached to imported module? Chris Angelico <rosuav@gmail.com> - 2011-05-04 07:47 +1000
      Re: Why do directly imported variables behave differently than those attached to imported module? Duncan Booth <duncan.booth@invalid.invalid> - 2011-05-04 08:44 +0000
    Re: Why do directly imported variables behave differently than those attached to imported module? Chris Rebert <clp2@rebertia.com> - 2011-05-03 15:11 -0700

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

FromDun Peal <dunpealer@gmail.com>
Date2011-05-03 09:31 -0700
SubjectWhy do directly imported variables behave differently than those attached to imported module?
Message-ID<d8d1d20e-2edd-49e5-917c-f338ef35006f@l18g2000yql.googlegroups.com>
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?

Thanks, D.

[toc] | [next] | [standalone]


#4554

FromChris Rebert <clp2@rebertia.com>
Date2011-05-03 09:57 -0700
Message-ID<mailman.1114.1304441878.9059.python-list@python.org>
In reply to#4548
On Tue, May 3, 2011 at 9:31 AM, Dun Peal <dunpealer@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

[toc] | [prev] | [next] | [standalone]


#4555

FromDaniel Kluev <dan.kluev@gmail.com>
Date2011-05-04 03:57 +1100
Message-ID<mailman.1115.1304441878.9059.python-list@python.org>
In reply to#4548
On Wed, May 4, 2011 at 3:31 AM, Dun Peal <dunpealer@gmail.com> wrote:
> Apparently, the `var` we imported from `foo` never got set, but
> `foo.var` on the imported `foo` - did. Why?

Because all names are references to some values, not other names (in
CPython, it means all names are PyObject*, and point directly to the
objects, not other pointers)

When you do `from foo import bar` it assigns globals()['bar'] of
current module to reference same value as `foo.bar`. Its now local
namespace name, not `foo` namespace, and therefore functions in `foo`
cannot modify this namespace.

Since ints are immutable, when you do `var = 1` you create new object
of type int, and re-assign `var` name to point to new object.

`foo.var`, on other hand, is a way to access `foo`'s own namespace, so
its exactly same name as globals()['var'] of `foo`.

-- 
With best regards,
Daniel Kluev

[toc] | [prev] | [next] | [standalone]


#4556

FromMel <mwilson@the-wire.com>
Date2011-05-03 13:00 -0400
Message-ID<ippcba$qt0$1@speranza.aioe.org>
In reply to#4548
Dun Peal 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?

They're different because -- they're different.  `foo.var` is defined in the 
namespace of the foo module.  Introspectively, you would access it as 
`foo.__dict__['var']` .

Plain `var` is in your script's namespace so you could access it as 
`globals()['var']` .  The values given to the vars are immutable integers, 
so assignment works by rebinding.  The two different bindings in 
foo.__dict__ and globals() get bound to different integer objects.

Note too the possible use of `globals()['foo'].__dict__['var'] .  (Hope 
there are no typos in this post.)

	Mel.

[toc] | [prev] | [next] | [standalone]


#4559

FromTerry Reedy <tjreedy@udel.edu>
Date2011-05-03 13:13 -0400
Message-ID<mailman.1117.1304442807.9059.python-list@python.org>
In reply to#4548
Your problem is reveal in the subject line. As discussed in many other 
threads, including a current one, Python does not have 'variables' in 
the way that many understand the term. Python binds names to objects.
Binding statements (assignment, augmented assignment, import, def, 
class, and others with 'as' clauses) all bind names to objects.

Suppose we both have address books. You copy all entries from my book to 
yours. Afterwards, I update an entry in my book. That does not change 
the now obsolete entry in your book.

On 5/3/2011 12:31 PM, Dun Peal wrote:
>      # module foo.py
>      var = 0
>
>      def set():
>          global var
>          var = 1

Module foo's dict now has two entries for 'var' and 'set' bound to int 0 
and a function. Note that 'set' is a builtin class name so not the best 
choice.
>
> Script using this module:

Script creates module '__main__'

>      import foo

This binds 'foo' to module foo in __main_'s dict.

>      from foo import *

This copies foo's dict to __main__'s dict.

>      print var, foo.var
>      set()

This changes foo's dict, rebinding 'var' to int 1. It does not change 
__main__'s dict. How could it? In the same way, 'var = 2' would leave 
foo's dict unchanged. __main__.var.

>      print var, foo.var
>
> Script output:
>
>      0 0
>      0 1

If instead of 'from foo import *', you had written 'from foo import var 
as rav', then perhaps you would not have been so surprised that 
__main__.rav and foo.var have independent fates.

You have discovered that using from x import * is a bad idea when module 
x has global names that get rebound.

-- 
Terry Jan Reedy

[toc] | [prev] | [next] | [standalone]


#4560

Fromharrismh777 <harrismh777@charter.net>
Date2011-05-03 12:24 -0500
Message-ID<vTWvp.23964$vC5.14171@newsfe01.iad>
In reply to#4548
Dun Peal wrote:
>      # module foo.py
>      var = 0
>
>      def set():
>          global var
>          var = 1

My two cents to add in addition to the correct accounts of [ Daniel, 
Chris, Mel] is that you might have a misunderstanding of var, generally.

Python has no variables--- in the way you think of them in other 
languages. Python only has references.

Var is not 'set' in the classical sense of the word...

var is a 'reference' (think C pointer, sort-of) to an object...   '0' 
and '1' are objects of type int and

var=0   means create a reference to object  int('0') called var.

a=b=0   a is a reference to object '0'
         b is a reference to object '0'

         a does not reference b

This rest of the discussion has to do with name spaces:

See:

http://docs.python.org/release/3.0.1/reference/datamodel.html?highlight=namespaces



[toc] | [prev] | [next] | [standalone]


#4566

FromDun Peal <dunpealer@gmail.com>
Date2011-05-03 11:51 -0700
Message-ID<b2d938e7-7df3-461b-a952-47a81000a335@26g2000yqa.googlegroups.com>
In reply to#4560
OK, I understand now.

`from foo import var` means "create a module-global name `var` inside
the current module, and have it point at the object `foo.var` is
pointing at (following its evaluation)".

Naturally, regardless of whether `foo.var` ever changes, the global
`var` of the current module still points at the original object
`foo.var` was pointing to at the time of the `var = foo.var`
assignment.

Thanks, D.

[toc] | [prev] | [next] | [standalone]


#4568

FromDun Peal <dunpealer@gmail.com>
Date2011-05-03 12:23 -0700
Message-ID<5299438d-611f-4a63-b1d8-4abe039ad5d4@k3g2000prl.googlegroups.com>
In reply to#4566
P.S. now I have to ask: is there a symbolic reference in Python, i.e.
a name foo that points to "whatever bar.baz is pointing at"?

Thanks, D.

[toc] | [prev] | [next] | [standalone]


#4570

FromDaniel Kluev <dan.kluev@gmail.com>
Date2011-05-04 06:55 +1100
Message-ID<mailman.1119.1304452508.9059.python-list@python.org>
In reply to#4568
On Wed, May 4, 2011 at 6:23 AM, Dun Peal <dunpealer@gmail.com> wrote:
> P.S. now I have to ask: is there a symbolic reference in Python, i.e.
> a name foo that points to "whatever bar.baz is pointing at"?

Well, you could easily simulate that with proxy object,
class SymbolicReference(object):
    def __init__(self, ns, name):
        self.__ns = ns
        self.__name = name

    def __get(self):
        return self.__ns[self.__name]

    def __getattribute__(self, attr):
        try:
            return object.__getattribute__(self, attr)
        except:
            return self.__get().__getattribute__(attr)

    def __repr__(self):
        return self.__get().__repr__()

    def __str__(self):
        return self.__get().__str__()

>>> a = 1
>>> b = SymbolicReference(globals(), 'a')
>>> b
1
>>> a = 10
>>> b
10


-- 
With best regards,
Daniel Kluev

[toc] | [prev] | [next] | [standalone]


#4576

FromChris Angelico <rosuav@gmail.com>
Date2011-05-04 07:47 +1000
Message-ID<mailman.1123.1304459240.9059.python-list@python.org>
In reply to#4548
On Wed, May 4, 2011 at 2:57 AM, Chris Rebert <clp2@rebertia.com> wrote:
> from foo import *
>
> can be thought of as essentially doing:
>
> import foo
> set = foo.set
> var = foo.var
> del foo

Here's a side point. What types will hold a reference to the enclosing
module (or at least its dictionary)? Would it be possible to use a
from import to load a module, then "lose" the module even though
you're using objects from it?

I am guessing that a function or class will hold such a reference,
because otherwise it would be a bit awkward for them to use any sort
of module-level state. Or do they not, and instead go look for their
module in sys.modules?

Chris Angelico

[toc] | [prev] | [next] | [standalone]


#4602

FromDuncan Booth <duncan.booth@invalid.invalid>
Date2011-05-04 08:44 +0000
Message-ID<Xns9EDB630F1EB14duncanbooth@127.0.0.1>
In reply to#4576
Chris Angelico <rosuav@gmail.com> wrote:

> Here's a side point. What types will hold a reference to the enclosing
> module (or at least its dictionary)? Would it be possible to use a
> from import to load a module, then "lose" the module even though
> you're using objects from it?
> 
> I am guessing that a function or class will hold such a reference,
> because otherwise it would be a bit awkward for them to use any sort
> of module-level state. Or do they not, and instead go look for their
> module in sys.modules?

A function object has a reference to the dictionary for the module in which 
it was defined; it needs this to access global variables. A class holds the 
name of the module but has no reference to the actual module itself.

Yes, it is quite possible to delete a module object, but it won't generally 
matter since any classes that are still referenced will prevent their 
methods being deleted and any functions or methods that are still 
accessible will keep the globals alive as long as required.

-- 
Duncan Booth http://kupuguy.blogspot.com

[toc] | [prev] | [next] | [standalone]


#4582

FromChris Rebert <clp2@rebertia.com>
Date2011-05-03 15:11 -0700
Message-ID<mailman.1129.1304460710.9059.python-list@python.org>
In reply to#4548
On Tue, May 3, 2011 at 2:47 PM, Chris Angelico <rosuav@gmail.com> wrote:
> On Wed, May 4, 2011 at 2:57 AM, Chris Rebert <clp2@rebertia.com> wrote:
>> from foo import *
>>
>> can be thought of as essentially doing:
>>
>> import foo
>> set = foo.set
>> var = foo.var
>> del foo
>
> Here's a side point. What types will hold a reference to the enclosing
> module (or at least its dictionary)? Would it be possible to use a
> from import to load a module, then "lose" the module even though
> you're using objects from it?
>
> I am guessing that a function or class will hold such a reference,
> because otherwise it would be a bit awkward for them to use any sort
> of module-level state. Or do they not, and instead go look for their
> module in sys.modules?

some_python_function.__globals__ is the exact reference you postulated.
Classes don't seem to hold such references; their methods do though
(by virtue of being function objects), which makes sense.

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

[toc] | [prev] | [standalone]


Back to top | Article view | comp.lang.python


csiph-web