Hi all,
I'm working with a program that operates largely with functions. The functions are all defined at the top with the main program starting ~Line 400.
I'm having issues today with writing output to files. Yesterday it was working fine. I'm not sure what I did.
Soooo... trying to debug. One thing I want to do is add test_counter to be +=1 every time Python starts going through a function to make sure the function is actually being called. At the end of the main program, I print test_counter to see the total (hoping for a nonzero number).
At the very top of the program, I added:
test_counter = 0
How best to proceed, now, with regard to local and global variables? My thought was that since I defined this as part of the main program (not inside any functions), it will be accessible to all inside or outside functions. Unfortunately, I just got:
UnboundLocalError: local variable 'test_counter' referenced before assignment
So instead, at the top I tried:
global test_counter
test_counter = 0
Same error.
Any thoughts?
Mark
Either get a development environment that supports breakpoints or learn how logging works. (preferably both).
Your problem is that test_counter += 1 will create an uninitialized local variable and then try to get the variable's value so it can add 1 and assign the result to the variable. So you are trying to use the value of test_counter before it is assigned a value.
"global test_counter" tells Python to get "test_counter" from the global scope. Putting this at the top of the file does nothing because you are already in the global scope. You need to put this line in each function that modifies the global "test_counter" variable.
test_counter = 0
def func():
global test_counter
test_counter += 1
This tells Python to get the "test_counter" variable assigned at the top of the module instead of creating a local variable.
Here is a decorator that will keep a count of how many times decorated functions are called.
class FuncCounter:
def __init__(self):
self.counter = {}
def observe(self, func):
self.counter[func.__name__] = 0
def wrapper(*args, **kwagrs):
self.counter[func.__name__] += 1
func(*args, **kwagrs)
return wrapper
func_counter = FuncCounter()
@func_counter.observe
def func1():
print("func1")
@func_counter.observe
def func2():
print("func2")
@func_counter.observe
def func3():
print("func3")
func1()
func1()
func2()
print(func_counter.counter)
Output:
func1
func1
func2
{'func1': 2, 'func2': 1, 'func3': 0}
Logging as mention and then is
loguru a star ✨
Quick example also if add
@logger.catch
decorator just before the main function.
Loguru is now catching all errors in the main function and in all nested functions.
from loguru import logger
def func_1(x, y):
logger.info("func_1 start")
result = x + y
return result
def func_2(name, email):
logger.info("func_2 start")
info = f'{name} {email}'
return info
@logger.catch
def main():
func_1(4, 9)
func_2('kent', '[email protected]')
if __name__ == "__main__":
main()
Output:
2021-09-24 21:00:13.457 | INFO | __main__:func_1:4 - func_1 start
2021-09-24 21:00:13.461 | INFO | __main__:func_2:9 - func_2 start
Make a error.
![[Image: VQv3g8.png]](https://imagizer.imageshack.com/v2/xq90/923/VQv3g8.png)
(Sep-24-2021, 04:53 PM)deanhystad Wrote: [ -> ]"global test_counter" tells Python to get "test_counter" from the global scope. Putting this at the top of the file does nothing because you are already in the global scope. You need to put this line in each function that modifies the global "test_counter" variable.
test_counter = 0
def func():
global test_counter
test_counter += 1
This tells Python to get the "test_counter" variable assigned at the top of the module instead of creating a local variable.
What's the best way to share a variable calculated in one function with another function--all while being able to also access it in the main program? Maybe initialize it in the main program and then specify them as global within each function?
Any variable in the module scope (global scope) can be seen by any function in the module. When Python is looking for a variable it first looks in the Local scope, followed by Enclosed scope, Global scope and Built-ins scope (LEGB). Enclosed scope occurs when you define a function inside of another function. The interior function can see the enclosing function's variables.
To set the value of a global variable from inside a function the function must declare the variable is global. If you don't declare the variable as global, variable assignment uses/creates a local variable.
Avoid using global variables. Programs with several global variables that are set from many different functions are difficult to debug. If you calculate a value in a function that is useful to other functions, the value should be returned.
This is bad
def circle(radius):
global circle_area, circle_circumference
circle_area = math.pi * radius**2
circle_circmference = 2 * math.pi * radius
circle(3)
print('Area =', circle_area)
This is better
def circle(radius):
return math.pi * radius**2, 2 * math.pi * radius
area, circumference = circle(3)
print('Area =', area)
And better yet
import math
class Circle():
def __init__(self, radius=0):
self.radius = radius
@property
def radius(self):
return self._radius
@radius.setter
def radius(self, value):
self._radius = value
self._area = math.pi * self._radius**2
self._circumference = 2 * math.pi * self._radius
@property
def area(self):
return self._area
@area.setter
def area(self, value):
self.radius = (value / math.pi)**0.5
@property
def circumference(self):
return self._circumference
@circumference.setter
def circumference(self, value):
self.radius = value / (2 * math.pi)
def __repr__(self):
return f'(Circle radius={self._radius}, circumference={self._circumference}, area={self._area})'
circle = Circle(3)
print(circle)
circle.area = math.pi * 25
print(circle)