How can I access global variable inside class in Python
Asked Answered
P

6

101

I have this:

g_c = 0

class TestClass():
    global g_c
    def run(self):
        for i in range(10):
            g_c = 1
            print(g_c)

t = TestClass()
t.run()

print(g_c)

how can I actually modify my global variable g_c?

Protozoology answered 30/5, 2012 at 10:26 Comment(4)
Note that the point of classes is to eliminate (truly) global state and to manage it within classes and objects.Haplo
You don't need to declare any global variable. Just declare g_c as a Class variable and then use print(t.g_c)Vostok
@agcala: that's what Marcin is already stating.Rivet
@agcala it's highly likely (not to say certain) that the OP is exposing a toy example here to demonstrate his question, and that other reasons lead him to use globalThrove
A
152

By declaring it global inside the function that accesses it:

g_c = 0

class TestClass():
    def run(self):
        global g_c
        for i in range(10):
            g_c = 1
            print(g_c)

The Python documentation says this, about the global statement:

The global statement is a declaration which holds for the entire current code block.

Auvergne answered 30/5, 2012 at 10:28 Comment(1)
The g_c = 0 does not have to stand in front of the function. You can as well create it after the function, the function will still know it, and there is no "referenced before assignment" error.Acroter
R
24

You need to move the global declaration inside your function:

class TestClass():
    def run(self):
        global g_c
        for i in range(10):
            g_c = 1
            print(g_c)

The statement tells the Python compiler that any assignments (and other binding actions) to that name are to alter the value in the global namespace; the default is to put any name that is being assigned to anywhere in a function, in the local namespace. The statement only applies to the current scope.

Since you are never assigning to g_c in the class body, putting the statement there has no effect. The global statement only ever applies to the scope it is used in, never to any nested scopes. See the global statement documentation, which opens with:

The global statement is a declaration which holds for the entire current code block.

Nested functions and classes are not part of the current code block.

I'll insert the obligatory warning against using globals to share changing state here: don't do it, this makes it harder to reason about the state of your code, harder to test, harder to refactor, etc. If you must share a changing singleton state (one value in the whole program) then at least use a class attribute:

class TestClass():
    g_c = 0

    def run(self):
        for i in range(10):
            TestClass.g_c = 1
            print(TestClass.g_c)  # or print(self.g_c)

t = TestClass()
t.run()

print(TestClass.g_c)

Note how we can still access the same value from the outside, namespaced to the TestClass namespace.

Rivet answered 30/5, 2012 at 10:29 Comment(3)
I gather you people are still programming in Python 2.7, aren't you? There is no need to declare any global variable at all. Look at my answer.Vostok
@agcala: that may well be, but the global statement, if used, doesn't go in the class, which is the point of the answer.Rivet
@agcala: I'm also not certain what you are referring to with the Python 2.7 remark. The only thing here that's specific to Python 2 is the print statement.Rivet
S
10

I understand using a global variable is sometimes the most convenient thing to do, especially in cases where usage of class makes the easiest thing so much harder (e.g., multiprocessing). I ran into the same problem with declaring global variables and figured it out with some experiments.

The reason that g_c was not changed by the run function within your class is that the referencing to the global name within g_c was not established precisely within the function. The way Python handles global declaration is in fact quite tricky. The command global g_c has two effects:

  1. Preconditions the entrance of the key "g_c" into the dictionary accessible by the built-in function, globals(). However, the key will not appear in the dictionary until after a value is assigned to it.

  2. (Potentially) alters the way Python looks for the variable g_c within the current method.

The full understanding of (2) is particularly complex. First of all, it only potentially alters, because if no assignment to the name g_c occurs within the method, then Python defaults to searching for it among the globals(). This is actually a fairly common thing, as is the case of referencing within a method modules that are imported all the way at the beginning of the code.

However, if an assignment command occurs anywhere within the method, Python defaults to finding the name g_c within local variables. This is true even when a referencing occurs before an actual assignment, which will lead to the classic error:

UnboundLocalError: local variable 'g_c' referenced before assignment

Now, if the declaration global g_c occurs anywhere within the method, even after any referencing or assignment, then Python defaults to finding the name g_c within global variables. However, if you are feeling experimentative and place the declaration after a reference, you will be rewarded with a warning:

SyntaxWarning: name 'g_c' is used prior to global declaration

If you think about it, the way the global declaration works in Python is clearly woven into and consistent with how Python normally works. It's just when you actually want a global variable to work, the norm becomes annoying.

Here is a code that summarizes what I just said (with a few more observations):

g_c = 0
print ("Initial value of g_c: " + str(g_c))
print("Variable defined outside of method automatically global? "
      + str("g_c" in globals()))

class TestClass():
    def direct_print(self):
        print("Directly printing g_c without declaration or modification: "
              + str(g_c))
        #Without any local reference to the name
        #Python defaults to search for the variable in globals()
        #This of course happens for all the module names you import

    def mod_without_dec(self):
        g_c = 1
        #A local assignment without declaring reference to global variable
        #makes Python default to access local name
        print ("After mod_without_dec, local g_c=" + str(g_c))
        print ("After mod_without_dec, global g_c=" + str(globals()["g_c"]))


    def mod_with_late_dec(self):
        g_c = 2
        #Even with a late declaration, the global variable is accessed
        #However, a syntax warning will be issued
        global g_c
        print ("After mod_with_late_dec, local g_c=" + str(g_c))
        print ("After mod_with_late_dec, global g_c=" + str(globals()["g_c"]))

    def mod_without_dec_error(self):
        try:
            print("This is g_c" + str(g_c))
        except:
            print("Error occured while accessing g_c")
            #If you try to access g_c without declaring it global
            #but within the method you also alter it at some point
            #then Python will not search for the name in globals()
            #!!!!!Even if the assignment command occurs later!!!!!
        g_c = 3

    def sound_practice(self):
        global g_c
        #With correct declaration within the method
        #The local name g_c becomes an alias for globals()["g_c"]
        g_c = 4
        print("In sound_practice, the name g_c points to: " + str(g_c))


t = TestClass()
t.direct_print()
t.mod_without_dec()
t.mod_with_late_dec()
t.mod_without_dec_error()
t.sound_practice()
Sparhawk answered 18/8, 2016 at 1:25 Comment(1)
One further thing to note: While a function being multiprocessed still cannot access the general global variables, the callback function can.Sparhawk
C
5
class flag:
    ## Store pseudo-global variables here

    keys=False

    sword=True

    torch=False


## test the flag class

print('______________________')

print(flag.keys)
print(flag.sword)
print (flag.torch)


## now change the variables

flag.keys=True
flag.sword= not flag.sword
flag.torch=True

print('______________________')

print(flag.keys)
print(flag.sword)
print (flag.torch)
Caballero answered 4/4, 2017 at 17:37 Comment(0)
S
2

It is very simple to make a variable global in a class:

a = 0

class b():
    global a
    a = 10

>>> a
10
Shebat answered 22/2, 2018 at 6:24 Comment(1)
Simple but unnecessary in this case.Vostok
P
0

I'd like to put together a few things I learned here (thanks to some brief but profound comments) and add my own one.

Q: How can I access a global variable from inside a class in Python?

A: By declaring it global inside the function that accesses it.

Why?: The global statement is a declaration which holds for the entire current code block. Nested functions and classes are NOT part of the current code block.

This does NOT work

class TestClass():

    global global_var

    def f1(self):
        global_var+=1

This does work

class TestClass():

    def f1(self):
        global global_var
        global_var+=1

However there is another 'case/situation'.

Q: How can I access a global variable declared on another module, from inside a class in Python?

A: By importing that module and calling it 'with the module'.

Why?: Globals belong to the module in which they are defined.

+Info on https://docs.python.org/3/reference/simple_stmts.html#the-global-statement

# module_vars.py

__all__ = ['global_var']

global_var=[]

This does NOT work

# main_program.py

from module_vars import *

class TestClass():

    def f1(self):
        global global_var
        global_var.append(1)

This does work

# main_program.py

import module_vars

class TestClass():

    def f1(self):
        module_vars.global_var.append(1)

A possible formula for both cases (local & imported)

# Place wherever you are going to use the global
if not 'global_var' in globals():
    log.info('global_var NOT in globals(). Try to find it in lt_globals.global_var ')
    global_var=lt_globals.global_var
else:
    log.info('global_var IN in globals(). Use it.')
    
    #global global_var # This still produces> SyntaxError: name 'global_var' is assigned to before global declaration
    global_var=globals()["global_var"]

A strange case.

This code (being global_var within globals())

if 'global_var' in globals():
    global global_var

global_var.append(1)

Produced this error.

SyntaxError: name 'global_var' is assigned to before global declaration

I workaround it with

if 'global_var' in globals():
    #global global_var # This doesn't seem to work.
    global_var = globals()['global_var']

global_var.append(1)

Note: All above was tested in Python 3.7

Pragmatism answered 11/12, 2022 at 17:10 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.