I need to change a variable each time the function is called. My function counts the number of time this function has been called:
def score_chart():
num_of_charts= 1
return num_of_charts
At the beginning num_of_charts
equals 0. Then I call the function and re-save num_of_charts
to be equal 1.
But if I call it second time, the result is still 1, while I m expecting to get 2.
num_of_charts = 0
num_of_charts = score_chart()
print (num_of_charts)
num_of_charts = score_chart()
print(num_of_charts)
1
1
Could you please help
CodePudding user response:
Use a parameter to get the old value.
def score_chart(num):
return num 1
num_of_charts = 0
num_of_charts = score_chart(num_of_charts)
print(num_of_charts)
num_of_charts = score_chart(num_of_charts)
print(num_of_charts)
CodePudding user response:
A general and useful way to count calls to any function is to define and use a function decorator. The decorator function maintains a count of the calls and this can be accessed whenever required.
def call_counter(func):
def keeper():
keeper.calls = 1
return func()
keeper.calls = 0
return keeper
@call_counter
def score_chart():
pass # function could do anything required
for i in range(4):
score_chart()
print(score_chart.calls)
which prints 4
CodePudding user response:
METHOD 1: You can use global variables for them to be accessible everywhere in the code (sometimes can be a bad practice)
Code:
def score_chart():
global num_of_charts
num_of_charts = 1
METHOD 2:
You can use num_of_charts
as a function argument and return it at the end of the function (you need to store that value in another variable outside the function)
Code:
def score_chart(num_of_charts):
num_of_charts = 1
return num_of_charts
new_num = score_chart( # put a number here )
After 1st function call you have to pass that new_num
as an argument and overwrite it with another value (only if you don't need to go back to previous values)
new_num = score_chart( # put a number here )
new_num = score_chart(new_num)
Also keep in mind that it is = 1
and not = 1
CodePudding user response:
The statement: My function counts the number of times this function has been called:
def score_chart():
num_of_charts= 1
return num_of_charts
is not true. Your function assigns to num_of_charts
the value 1
.
What you actually intended to do is to increase the value by one using num_of_charts = 1
but had put the
at the right side of =
instead of the left side.
This is the reason why the returned result was always 1
.
In addition to this above you need to know that in Python it is important to be aware of the local and global scope of variable names used in a function (check out the docs on it). Not being aware of that leads very often to confusion and wrong expectations. stackoverflow is full of questions which resulted from this kind of confusion.
As long as you only use a variable name in a function it will represent the global value assigned outside of the function before calling it. This is the reason why:
def score_chart_1():
return num_of_charts
is able to return the current value assigned to num_of_charts
outside the function so that:
num_of_charts = 2
print(score_chart_1())
num_of_charts = 3
print(score_chart_1())
will print 2
and 3
.
If you in your function try to assign a value to a variable name using num_of_charts = 1
the variable name changes its scope from global to local in the function.
Notice that num_of_charts = 1
is equivalent to num_of_charts = num_of charts 1
and Python needs to know the value of num_of_charts
to increase it by one. But usage of the assignment operator =
with num_of_charts
changed the scope of num_of_charts
to local where num_of_charts
does not yet have a value and because of that an:
UnboundLocalError: local variable 'num_of_charts' referenced before assignment
will be raised.
The Error
can be avoided by declaring the scope of a variable to be global in the function using as first function statement (as first is the usual convention in Python):
global num_of_charts
With this statement above there will be no UnboundLocalError
and the function will then work as expected.
Even is this changes will solve your problem this kind of solution is considered to be a bad programming style and the approach of passing a counter parameter to the function and updating it with the return value in order to pass the changed value on next function call a better one (see another answers for code of this approach).
Best approach to achieve what you want would be to use a Python class where it would easily be possible to count any function calls. See code below for an example of code (choice of variable names should be sufficient as explanations what the code does):
class Charts:
def __init__(self, list_with_charts):
self.list_with_charts = list_with_charts
self.list_with_scores = [0]*len(list_with_charts)
def score_chart(self, chart_index):
return self.list_with_scores[chart_index]
def show_chart(self, chart_index):
# some code to present/show the chart
self.list_with_scores[chart_index] = 1
objCharts = Charts(['chart0.ppt', 'chart1.ppt', 'chart2.ppt'])
objCharts.show_chart(0)
objCharts.show_chart(0)
objCharts.show_chart(2)
objCharts.show_chart(2)
objCharts.show_chart(2)
print(objCharts.score_chart(2)) # gives 3
For the sake of completeness it is worth to mention two another kinds of approaching counting function calls (see answer by user19077881):
- using function closure
- using a function decorator