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.
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
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_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
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 ) state  + = 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 =  @wraps (func) def wrapper (* args, ** kwargs): count  + = 1 func (* args, ** kwargs) print (count ) 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 = ): counter  + = 1 return counter  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