SidGabriel
SidGabriel

Reputation: 185

local variable referenced before assignment / Python

I'm trying to design a counter which would be incremented each time an action is done. Something like this:

def action_on_accounts(self, accounts):
    for account in accounts[9:]: 
        try:
            self.browser.get(account)
            time.sleep(5)
            action_button = self.browser.find_element_by_xpath(u'//button[contains(@class, "Heart")]').click()
            counter_var = self.count_actions(counter_var)
            print(counter_var)
        except selenium.common.exceptions.NoSuchElementException:
            break

def count_actions(self, counter_var):
    return counter_var + 1

def main(self):

    counter_var = 0
    (...)

This is throwing a UnboundLocalError: local variable 'counter_var' referenced before assignment

I have read that I have to declare counter_var as global inside function and did this:

def count_actions(self, counter_var):
    global counter_var
    return counter_var + 1

It was throwing SyntaxError: name 'counter_var' is parameter and global error.

So I tried this :

def count_actions(self):
    global counter_var
    return counter_var + 1

Calling it this way :

counter_var = self.count_actions()
print(counter_var)

And now I have NameError: name 'counter_var' is not defined....

Please assist

Upvotes: 1

Views: 8375

Answers (3)

Well if you really want to use a global variable (which I advice against) you can do it with the global keyword. You need that keyword to declare the variable. Example:

def action_on_accounts():
    global counter_var #declare the variable
    counter_var = count_actions(counter_var)
    print(counter_var)

def count_actions(cv):
    global counter_var  #you do not have to declare the variable here since we are theoretically in the right scope
    print(counter_var) #just to check that is global
    return cv + 1 #no need to declare since it is a parameter

if __name__ == "__main__":
    counter_var = 0
    action_on_accounts() #1
    action_on_accounts() #2
    print(counter_var) #will return 2

I tested this in the IPython console (Python 3.6).

However I strongly recommend that you use attributes of classes to do the same effect (as in use self not global). Global variables may create bad code.

Upvotes: 1

hegash
hegash

Reputation: 863

An alternative, simpler solution is to use python's built-in enumerate(); It exists so we don't have to make our own functions. You can then set the count equal to a global variable declared outside your functions

So the code would look like this:

counter_var = 0
def action_on_accounts(self, accounts):
    for count, account in enumerate(accounts[9:]): 
            global counter_var
            counter_var = count
            print(counter_var)

def main(self):
    global counter_var
    counter_var = 0
    (...)

Upvotes: 4

busybear
busybear

Reputation: 10590

You should consider defining counter_var as an attribute: self.counter_var. It'll be accessible throughout your class (assuming that's what's going on). You won't have to provide it explicitly as an argument in your functions/methods and no need to worry about global variables.

def action_on_accounts(self, accounts):
    for account in accounts[9:]: 
        try:
            self.browser.get(account)
            time.sleep(5)
            action_button = self.browser.find_element_by_xpath(u'//button[contains(@class, "Heart")]').click()
            self.count_actions()
            print(self.counter_var)
        except selenium.common.exceptions.NoSuchElementException:
            break

def count_actions(self):
    self.counter_var += 1

def main(self):

    self.counter_var = 0
    (...)

You'll probably want to initialize self.counter_var with your class however.

Upvotes: 2

Related Questions