Lunkle
Lunkle

Reputation: 145

Changing variables across files Python

Heyo, I've run upon a problem. So I have three files:

  1. Main Program
  2. Functions
  3. Data

And I want the Main Program to call a function from the Functions module, which changes a variable in Data. Then I need to use the new variable elsewhere in the Main Program.

This is what I want, shown as a simplified demonstration program:

The Data file:

#data.py
#just an short depiction of my actual file
text = ""

The Functions file:

#functions.py
from data import *

def printHi():
    global text
    text = "hi"
    print(text)

The Main Program:

#mainProgram.py
from functions import *
from data import *

printHi()
print(text)

What I expected would happen would be that when I run the Main Program:

The Functions file and Data file is imported.

Then it calls the "printHi" method from the Functions file.

The variable "text" from the Data file is assigned "hi", and is printed.

The the Main Program prints the "text" variable.

And I supposed that the text variable would be "hi". However, to my disappointment, it prints blank. It does indeed print the initial text value.

I really have NO idea why this is so. Shouldn't the text variable have already been changed? Could you please explain what part about my program is wrong and how to correct it?

Upvotes: 2

Views: 1088

Answers (2)

Joooeey
Joooeey

Reputation: 3892

Cool, we have a lot of people saying "don't do this!". Well, what should you do then? The good way to do this is to pass the text variable into the function and out of it. Like so:

The Data file:

#data.py
#just an short depiction of my actual file
text = ""

The Functions file:

#functions.py
from data import *

def printHi(atext):
    atext = "hi"
    print(atext)
    return atext

The Main Program:

#mainProgram.py
from functions import *
from data import *

text = printHi(text)
print(text)

That solves your problem. You should probably also get rid of the * imports as the other answer suggests but that's a philosophical question.

Upvotes: 2

Adam Smith
Adam Smith

Reputation: 54273

The short answer is simply not to do this. It's a Bad Idea for all the reasons that global variables are always bad ideas: because they lead to stack overflow questions that read like "If I do this thing I shouldn't do, it does something I didn't expect -- why did it do that?" Whose easiest answer is, as you've now read, "That's why you shouldn't do that thing."

The long answer is a bit beyond me without spending a whole lot more time on the matter, but the longer answer is simple enough. When you do those "star" imports (from modulename import *) you're rebinding the name of the variable. What functions.printHi thinks of as text is not data.text but actually functions.text. When it's changed in printHi, it changes functions.text which should still be okay, since mainProgram is also importing functions.

However remember that mainProgram ISN'T actually importing functions, it's from functions import *'ing. That means what mainProgram thinks of as text is neither data.text nor functions.text, but mainProgram.text. When functions.printHi changes functions.text, it doesn't touch mainProgram.text.

The short answer applies here because these sorts of pitfalls are non-obvious unless you can think deeply enough about your code to understand them. If you are able to think that deeply about your code, you should be able to write something that can sidestep such pitfalls entirely. For instance: "global mutable state" is generally a bad thing. Avoid it.

To just make this work, drop all your "star" imports. The following code works:

# functions.py
import data


def printHi():
    # plus! You don't need the `global` anymore.
    data.text = "hi"
    print(data.text)

 

# mainProgram.py
import functions
import data


functions.printHi()  # prints "hi" from inside functions.printHi
print(data.text)     # also prints "hi"

Upvotes: 3

Related Questions