Search code examples
pythonvariablesgloballocaldiscord.py

"UnboundLocalError: local variable 'x' referenced before assignment" But it's a global variable


I am making a Python Discord bot with discord.py. I am relatively new to Python but have about eight years of experience with other languages. My problem is that I get the UnboundLocalError: local variable 'prefix' referenced before assignment even though I have defined prefix as a global variable. (I am using Python 3.6.8)

I have tried defining the variables outside the on_ready function, but I get the same result.

import discord;

client = discord.Client();

@client.event
async def on_ready():
  print('Loading complete!')
  ...
  global prefix
  prefix = 'hello world'

@client.event
async def on_message(message):

  if message.author == client.user:
    return

  messageContents = message.content.lower()
  splitMessage = messageContents.split()
  try:
    splitMessage[0] = splitMessage[0].upper()lower()
  except:
    return
  if splitMessage[0]==prefix:
    ...
    (later in that if statement and a few nested ones)
    prefix = newPref

client.run('token')

I expected the output would be that it runs the code within the if statement, but instead I get the error UnboundLocalError: local variable 'prefix' referenced before assignment and no code is run.

The only thing I can think of being the problem is prefix = newpref. I tried:

global prefix
prefix = newpref

But then I got the error: SyntaxError: name 'prefix' is used prior to global declaration and the bot didn't start at all. What should I do?


Solution

  • According to the official docs

    This is because when you make an assignment to a variable in a scope, that variable becomes local to that scope and shadows any similarly named variable in the outer scope.

    Short version:

    You need to declare your global variable outside the scope of your functions such as

    #declaring the global variable
    x = 10
    def foobar():
        #accessing the outer scope variable by declaring it global
        global x
        #modifying the global variable
        x+=1
        print(x)
    #calling the function
    foobar()
    

    Long version:

    Basically, everything in python is an object and collections of those objects are called namespaces.

    Each module has its own private symbol table, which is used as the global symbol table by all functions defined in the module. Thus, the author of a module can use global variables in the module without worrying about accidental clashes with a user’s global variables.

    So when you run your bot script, python treats it as a module that is running as the main script, with its own global scope.
    When you declare a variable in a global scope, to use it in local scopes of certain functions you need to use the keyword global to access that global scope of your module.

    Also, python does not require semi-colons to terminate statements (such as client = discord.Client();). Semicolons can be used to delimit statements if you wish to put multiple statements on the same line.