Home python Global variables in Python: keep a local variable from call to function...

Global variables in Python: keep a local variable from call to function call

Author

Date

Category

I have a function that needs to store a value from call to call, and that value is only used in that function. How do I use global variables correctly in Python? I’ve tried writing something like this:

someGlobalVar = 0
def incrimentGlobalVar ()
  someGlobalVar = someGlobalVar + 1

Answer 1, authority 100%

There are several ways to implement this behavior.

Global Variables

The first thing that comes to mind is to use global variables.
It is important to take into account that global variables read access

def func1 ():
  print (x)
x = 10
func1 () # 10

but simple write use is not allowed:

def func2 ():
  y = 20 # creates a local variable, does not change the global
y = 10
func2 ()
print (y) # 10

Moreover, when we try to access a variable first for reading, then for writing, we will receive an error:

def func3 ():
  print (z)
  z = 20
z = 10
func3 () # UnboundLocalError: local variable 'z' referenced before assignment

This is due to the fact that using the assignment to the variable z denotes it as local (as in case 2). An attempt to display the value of a local variable that has not yet been assigned a value generates this error.

A similar example is just given in your question. There, too, the someGlobalVar variable is defined as local, because the assignment is performed. Since this assignment uses first reading the value of the not yet initialized someGlobalVar variable, we get the same error.


For this example to work, you must first mark the variable as global :

def func4 ():
  global w
  print (w)
  w = 20
w = 10
func4 () # 10
print (w) # 20

The same will work in your case.


Using the function field

The second way you can think of is using a function object to store the state of the function.

def func5 ():
  if not hasattr (func5, '_state'): # initialize value
    func5._state = 0
  print (func5._state)
  func5._state = func5._state + 1
# until the first call of the function, the value is not set
# print (func5._state) # AttributeError: 'function' object has no attribute '_state'
func5 () # 0
print (func5._state) # 1

The convenient thing about this method is that the value is associated with the function itself.

You should be careful when naming such function fields, as in Python 2 functions have standard fields with names that do not start with two underscores, for example, func_closure , func_code etc. They all begin with func_ , so the main thing is not to use this prefix and not to start the field name with __ , otherwise the chance of name collisions is practically zero.


Using a class with function behavior

The third way is to create a class with function behavior. This is the most convenient and safe, in my opinion, way to implement such behavior. Just create a class and overload its __call__ method:

class FuncCreator:
  def __init __ (self, start_state):
    self.state = start_state
  def __call __ (self):
    print (self.state)
    self.state + = 1
func6 = FuncCreator (0)
print (func6.state) # 0
func6 () # 0
print (func6.state) # 1

This increases the amount of code, but adds to the convenience of using the functionality of the class.


Using a mutable object as the default value for the parameter

The fourth way is to create a function that has an optional parameter that uses the mutable value as its state:

def func7 (state = []):
  if not state:
    state.append (0)
  print (state [0])
  state [0] + = 1
func7 () # 0
func7 () # 1

Any mutable object can be used as a state object. This makes use of the fact that all defaults are assigned once.


Using a decorator to do the computation

Going back to the original example, it might also be convenient to use decorators to count the number of function calls. This will also allow you to reuse the code.

For Python 3, the code might look like this:

from functools import wraps
def call_count (func):
  count = 0
  @wraps (func)
  def wrapper (* args, ** kwargs):
    nonlocal count
    count + = 1
    func (* args, ** kwargs)
print (count)
  return wrapper

There is no nonlocal in Python 2, but mutable variables can be used:

from functools import wraps
def call_count (func):
  count = [0]
  @wraps (func)
  def wrapper (* args, ** kwargs):
    count [0] + = 1
    func (* args, ** kwargs)
    print (count [0])
  return wrapper

It will be used as follows:

@ call_count
def f ():
  pass
f () # 1
f () # 2

If you wish, you can combine this method with any of the ones described earlier.


Of all the above methods, I would recommend using classes (since a stateful function is already more like a class than a function) or a function field if you need to quickly add functionality to your code.


Answer 2, authority 27%

If a global variable is changed in a function, it must be declared.

someGlobalVar = 0
def incrimentGlobalVar ()
  global someGlobalVar
  someGlobalVar = someGlobalVar + 1

If a global variable is used for read-only, then it does not need to be declared.

def print_someGlobalVar ():
  print someGlobalVar

Answer 3, authority 15%

Global variables are evil, better to do this:

def incrimentGlobalVar ():
  incrimentGlobalVar._someVar = incrimentGlobalVar._someVar + 1 if hasattr (incrimentGlobalVar, "_someVar") else 0

Answer 4, authority 9%

In Python 3, you can use nonlocal with closure :

def make_counter ():
  i = 0
  def counter (): # counter () is a closure
    nonlocal i
    i + = 1
    return i
  return counter
increment = make_counter ()
print (increment (), increment ()) # - & gt; 12

In earlier versions, it was possible to emulate nonlocal using a modifiable parameter:

def increment (counter = [0]):
  counter [0] + = 1
  return counter [0]
print increment (), increment () # - & gt; 12

You can use an explicit object:

import functools
import itertools
increment = functools.partial (next, itertools.count (1))

Used here existing function itertools.count () , you can define your own:

def count (i = 0):
  while True:
    yield i
    i + = 1

Programmers, Start Your Engines!

Why spend time searching for the correct question and then entering your answer when you can find it in a second? That's what CompuTicket is all about! Here you'll find thousands of questions and answers from hundreds of computer languages.

Recent questions