0

I have read the documentation and also this comprehensive answer but something doesn't work as I expect. I hoped to use from set_stuff_up import * as basically an "include" statement to define some boilerplate globals and functions, but something doesn't work as I'd expect. Here is set_stuff_up.py:

public_name = None
def set_public_name():
    global public_name # makes no diff
    public_name = 'HELLO DERE'

However the following code:

from set_stuff_up import *
print('public_name is',public_name)
set_public_name()
print('public_name is',public_name)

produces the output:

public_name is None
public_name is None

In other words, from set_stuff_up import * did bind public_name "in the local namespace for the scope where the import statement occurs" but somehow the function set_public_name operates on a different public_name, regardless of the global statement.

Can somebody clarify the way the namespaces are operating in this case? And is there a way to have the imported function operate on the imported public name?

Community
  • 1
  • 1
user405
  • 579
  • 7
  • 13

2 Answers2

2

It's important to understand that Python variables are names referring to values. The globals of a module are names that refer to values. When you use from set_stuff_up import *, that means, make names in this module that refer to the same values as the corresponding names in set_stuff_up. So now you have two names, set_stuff_up.public_name, and my_module.public_name, both referring to the same value (None in this case). When you run set_public_name, you are reassigning set_stuff_up.public_name to refer to a new value. Your other name, my_module.public_name is unaffected.

Names cannot refer to other names, only to values. Your situation here is no different than:

a = 1
b = a
a = 2

You don't expect b to equal 2 at this point. Assigning to a doesn't affect any other name that shares the same value as a.

For more detail on this, see Facts and Myths about Python Names and Values.

There isn't a way to organize your code to get the exact effect you are looking for. You could use this:

import set_stuff_up
print('public_name is', set_stuff_up.public_name)
set_stuff_up.set_public_name()
print('public_name is', set_stuff_up.public_name)
Ned Batchelder
  • 364,293
  • 75
  • 561
  • 662
  • Bitten again by that... this is even more subtle than the "default_arg=[]" issue. Because the general behavior and the official doc all strongly suggest that `from x import y` does NOT create a namespace `x`, but just "binds" the name `y` in the executing namespace. That's why I supposed that a global in `x` would be a global in the caller also. I thought I "got it" about namespaces, but I also thought "aha, from x import gets around that namespace thing." – user405 Oct 25 '14 at 15:30
  • Every module is its own namespace. There is no process-wide namespace larger than a module. – Ned Batchelder Oct 25 '14 at 17:07
0

set_public_name() global just apply in the set_stuff_up.py scope. from set_stuff_up import * is only import the value not the reference.

set_stuff_up.py:

public_name = None
print('-- set_stuff_up.py "public_name" id',id(public_name)
def set_public_name():
    global public_name # makes no diff
    print('-- before set_public_name "public_name" id',id(public_name)
    public_name = 'HELLO DERE'
    print('-- after set_public_name "public_name" id',id(public_name)

try

from set_stuff_up import *
print('*** befor call set_public_name public_name id:',id(public_name) )
set_public_name() 
print('*** after call set_public_name public_name id:',id(public_name) )

result

-- set_stuff_up.py "public_name" id 505816928
*** befor call set_public_name public_name id: 505816928
-- before set_stuff_up.py set_public_name "public_name" id 505816928
-- after set_stuff_up.py set_public_name "public_name" id 12543344
*** after call set_public_name public_name id: 505816928

and

import set_stuff_up 
print('### befor call set_public_name public_name id:',id(public_name) )
set_stuff_up.set_public_name() 
print('### after call set_public_name public_name id:',id(public_name) )

result

-- set_stuff_up.py "public_name" id 505816928
### befor call set_stuff.set_public_name public_name id: 505816928
-- before set_stuff_up.py set_public_name "public_name" id 505816928
-- after set_stuff_up.py set_public_name "public_name" id 12543344
### after call set_stuff.set_public_name public_name id: 12543344
MuSheng
  • 341
  • 2
  • 5