Locane
Locane

Reputation: 3144

Global variables and module importing

I've been using Python for years, and creating new modules for distribution is still confusing and eludes me; and it is REALLY frustrating. I need an expert to explain this.

I recently discovered that setting a global variable in a sub-module behaves differently depending on how the module is imported in the __init__.py file.

I have something like this set up:

prime.py

 import sub
 sub.somevar = False
 sub.show()

sub.py

somevar = True
def show():
    global somevar
    print("somevar is {}".format(somevar))

This code produces the expected output:

somevar is False.

when main.py and sub.py are in the same directory. When I make sub a separate installable module with setuptools, it stops working.

My sub installable module directory structure looks like this:

# ls
setup.py sub README.md
# ls sub
__init__.py sub.py 

Where __init__.py contains the text:

from .sub import *

This setup appears to work great for installing and distributing the module, for both Python2 and Python3.

The problem is that now global variable setting is broken when I import it with prime.py; any attempt to set somevar from prime.py does not change the variable for functions of sub.py as is intended. I get the output:

somevar is True

What the hell is going on here? Why is python module importing so finicky?

Upvotes: 0

Views: 93

Answers (2)

Scientist42
Scientist42

Reputation: 77

For quick fix, you can simply use "setter" "getter" behavior:

prime.py

import sub
sub.set_somevar(False)
myFalseVar = sub.get_somevar()

sub.py

somevar = True
def get_somevar():
    global somevar
    return somevar

def set_somevar(var):
    global somevar
    somevar = var

Upvotes: 0

Sraw
Sraw

Reputation: 20264

It is not related to your project structure, but only how you import it.

I think it is easy to understand. As somevar is a value type when you use from x import * which implicitly from x import somevar, you get a copy of somevar in your current namespace.

And because it is just a copy, changing it won't change the somevar in your submodule.

But if somevar is a list, like:

# In sub.py
somevar = [True]

And you change it by

# In prime.py
somevar[0] = False

Then it will work.

Upvotes: 1

Related Questions