10

I'm running into an issue where a global variable isn't "remembered" after it's modified in 2 different functions. The variable df is supposed to be a data frame, and it doesn't point to anything until the user loads in the right file. This is similar to something I have (using pandas and tkinter):

global df

class World:

    def __init__(self, master):
        df = None
        ....

    def load(self):
        ....
        df = pd.read_csv(filepath)

    def save(self):
        ....
        df = df.append(...)

save() is always called after load(). Thing is, when I call save(), I get the error that "df is not defined." I thought df got its initial assignment in init(), and then got "updated" in load()? What am I doing wrong here?

Arya McCarthy
  • 8,554
  • 4
  • 34
  • 56
Axioms
  • 505
  • 2
  • 4
  • 11

3 Answers3

18

You have to use global df inside the function that needs to modify the global variable. Otherwise (if writing to it), you are creating a local scoped variable of the same name inside the function and your changes won't be reflected in the global one.

p = "bla"

def func():
    print("print from func:", p)      # works, readonly access, prints global one

def func1():
    try: 
        print("print from func:", p)  # error, python does not know you mean the global one
        p = 22                        # because function overrides global with local name   
    except UnboundLocalError as unb:
        print(unb)
        
def func2():
    global p
    p = "blubb"                       # modifies the global p

print(p)
func()
func1()
print(p)
func2()
print(p)

Output:

bla   # global

print from func: bla    # readonly global

local variable 'p' referenced before assignment  # same named local var confusion

bla    # global
blubb  # changed global
Anton Menshov
  • 2,266
  • 14
  • 34
  • 55
Patrick Artner
  • 50,409
  • 9
  • 43
  • 69
  • Oh, so do I need to declare it every time I need to call it? There isn't a way for it to be "universally" remembered inside a class? – Axioms Apr 08 '18 at 08:20
  • @Axioms if you want it to be available for all functions in a class you can make it a class variable. Other than that nothing much to do but to write it in every function needed – Osman Mesut Ozcan Apr 08 '18 at 08:22
  • @Axioms I prefer to not use globals at all - I mostly provide them as parameters to functions _or_ put them as member variables inside classes. – Patrick Artner Apr 08 '18 at 08:26
  • So if I set ``x = "hello"`` right after I declare a class (i.e. class variable), then would that ``x`` be ``"hello"`` in every function of that class? – Axioms Apr 08 '18 at 08:28
  • @Axioms That would be a "static" Class-Variable, its shared between instances of that class, one changes it - all gets the change. Unless you need to create 20 different worlds, accessing the same `df` I would probably use a `self.df = None` inside the `__init__(self, ... )`, load it inside load `self.df = pd.read_csv(...)` etc. – Patrick Artner Apr 08 '18 at 08:29
  • Ah, guess I was confusing global variables with class variables. Got it, thank you. – Axioms Apr 08 '18 at 08:36
9

for anyone coming here using python3 - try using nonlocal instead of global - a new construct introduced in python3 which allows you to mutate and read global variables in local scope

raGhavSri
  • 165
  • 2
  • 8
7

You have to use the global keyword inside the function rather than outside. All the df that you have defined inside your function are locally scoped. Here is the right way -

df = pd.DataFrame() # No need to use global here

def __init__(self, master):
    global df # declare here
    df = None
....

def load(self):
    global df # declare here
    ....
    df = pd.read_csv(filepath)

def save(self):
    global df # declare here
    ....
    df = df.append(...)
Vivek Kalyanarangan
  • 8,951
  • 1
  • 23
  • 42