Home > Blockchain >  Function takes wrong variable python
Function takes wrong variable python

Time:11-09

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
  • Related