简体   繁体   中英

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

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
    (...)

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.

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM