Непоследовательная ошибка «UnboundLocalError: локальная переменная, на которую ссылаются до назначения», с переменной, определенной внутри функции - PullRequest
0 голосов
/ 23 ноября 2018

Я делал простую текстовую RPG с использованием Python и иногда получал ошибки, но не каждый раз.

Иногда, когда я прохожу последовательность, чтобы попасть в бой, мне выдается следующая ошибка:

UnboundLocalError: local variable referenced before assignment

или

enemy name not defined

Ошибка всегдапроисходит из строка 101 , внутри функции fightScreen ():

enemy["level"] = player["level"]

Я уже гуглил и искал в переполнении стека и обнаружил, что это проблема с функциями, пытающимися вместо этого переопределить переменнуюиспользования одного из ранее, но в моем случае переменная (словарь) определяется внутри самой функции.

Я не понимаю, что это вызывает, и особенно, почему это происходит только иногда

Минимальный пример (я думаю, этот кусок может быть связан с проблемой):

player = {
  "name" : "player",
  "level" : 1,
  "ATK" : 5,
  "DEF" : 5,
  "CurHP" : 10,
  "MaxHP" : 10,
  "CurINV" : 0,
  "MaxINV" : 20
}

def randomEnemy():
  monsters = ['Goblin','Slime']
  random_enemy = random.choice(monsters)
  return random_enemy

def fightScreen():
  if randomEnemy() == "Goblin":
    enemy = { #GOBLIN
      "name" : "Goblin",
      "level" : 1,
      "ATK" : 2,
      "DEF" : 2,
      "CurHP" : 5,
      "MaxHP" : 5
    }
  elif randomEnemy() == "Slime":  
    enemy = { #SLIME
      "name" : "Slime",
      "level" : 1,
      "ATK" : 1,
      "DEF" : 3,
      "CurHP" : 5,
      "MaxHP" : 5
    }
  enemy["level"] = player["level"]
  enemy["ATK"] = (enemy["level"] * enemy["ATK"])
  enemy["DEF"] = (enemy["level"] * enemy["DEF"])
  enemy["MaxHP"] = (enemy["level"] * enemy["MaxHP"])
  enemy["CurHP"] = enemy["MaxHP"]
  playerStatus()

Вот полный код

import re
import random
import os

#player values
player = {
  "name" : "player",
  "level" : 1,
  "ATK" : 5,
  "DEF" : 5,
  "CurHP" : 10,
  "MaxHP" : 10,
  "CurINV" : 0,
  "MaxINV" : 20
}

#predefined variables
loop_i = 1
answer_yes = {'yes', 'y'}
answer_no = {'no', 'n'}
go_world = {'world', 'w'}
go_home = {'home', 'h'}
go_church = {'church', 'c'}
go_blacksmith = {'blacksmith', 'b'}
go_return = {'return', 'run', 'r'}
go_fight = {'fight', 'f'}

#defined functions for input
#ask a question and filter answer from non-letters and spaces
def questionAsked(question):
  inputRaw = input(question + ':')
  inputFiltered = re.sub('[^a-zA-Z0-9]+', '', inputRaw)
  return inputFiltered

def cls():
  #os.system('cls' if os.name=='nt' else 'clear')
  print('\n' * 30)

def playerStatus():
  print ("ATK ",player["ATK"]," | DEF ",player["DEF"]," | HP ",player["CurHP"],"/",player["MaxHP"]," | INV ",player["CurINV"],"/",player["MaxINV"]," | LV",player["level"],sep='')

def randomEnemy():
  monsters = ['Goblin','Slime']
  random_enemy = random.choice(monsters)
  return random_enemy

# screens-------------------------
#enemy prints
def printGoblin():
  print ("--------------------[FIGHT]-------------------")
  print ("|                .                            |")
  print ("|               |                  | .        |")
  print ("|              |                  |//         |")
  print ("|             |  \       /       /  /         |")
  print ("|             |___\     /____  /   /          |")
  print ("|            | \°_\     /°__/ /   /           |")
  print ("|            '               |  /             |")
  print ("|             |   (° °)       -               |")
  print ("|              | _________    |               |")
  print ("|               ||ˇˇˇˇˇˇˇ|   .|               |")
  print ("|               | -------   |                 |")
  print ("|                |_________|                  |")
  print ("|_____________________________________________|")

def printSlime():
  print ("--------------------[FIGHT]-------------------")
  print ("|                       ______                |")
  print ("|                ______/      \_              |")
  print ("|              _/               \             |")
  print ("|             /    \     /       \_           |")
  print ("|            /    0       0        \          |")
  print ("|           /                       \         |")
  print ("|           /        ____            |        |")
  print ("|          /                         |        |")
  print ("|          /                          \       |")
  print ("|         /____________________________\      |")
  print ("|                                             |")
  print ("|                                             |")
  print ("|_____________________________________________|")

# fighting -----------------------
def fightScreen():
  if randomEnemy() == "Goblin":
    enemy = { #GOBLIN
      "name" : "Goblin",
      "level" : 1,
      "ATK" : 2,
      "DEF" : 2,
      "CurHP" : 5,
      "MaxHP" : 5
    }
  elif randomEnemy() == "Slime":  
    enemy = { #SLIME
      "name" : "Slime",
      "level" : 1,
      "ATK" : 1,
      "DEF" : 3,
      "CurHP" : 5,
      "MaxHP" : 5
    }
  enemy["level"] = player["level"]
  enemy["ATK"] = (enemy["level"] * enemy["ATK"])
  enemy["DEF"] = (enemy["level"] * enemy["DEF"])
  enemy["MaxHP"] = (enemy["level"] * enemy["MaxHP"])
  enemy["CurHP"] = enemy["MaxHP"]
  playerStatus()
  if enemy['name'] == "Goblin": #If enemy is GOBLIN
    printGoblin()
    print ("[",enemy["name"], ", LV", enemy["level"]," | HP ",enemy["CurHP"], "/",enemy["MaxHP"],"] ", "Fight (f) | Run (r)", sep='')
    print ("-----------------------------------------------")
    while enemy["CurHP"] > 0:
      userInput = questionAsked("What will you do?").lower()
      if userInput in go_fight:
        cls()
        printGoblin()
        print("You dealt ", (player["ATK"] - enemy["DEF"]) ," damage", sep='')
        enemy["CurHP"] = enemy["CurHP"] - (player["ATK"] - enemy["DEF"])
        if enemy["CurHP"] <= 0:
          print ("You won!")
          input("Press ENTER to go back")
          cls()
          Main()
        else:
          input("Press ENTER to continue")
          cls()
          printGoblin()
          print ("[",enemy["name"], ", LV", enemy["level"]," | HP ",enemy["CurHP"], "/",enemy["MaxHP"],"] ", "Fight (f) | Run (r)", sep='')
          print ("-----------------------------------------------")
      elif userInput in go_return:
        cls()
        Main()
        break

  elif enemy['name'] == "Slime": #If enemy is SLIME
    printSlime()
    print ("[",enemy["name"], ", LV", enemy["level"]," | HP ",enemy["CurHP"], "/",enemy["MaxHP"],"] ", "Fight (f) | Run (r)", sep='')
    print ("-----------------------------------------------")
    while enemy["CurHP"] > 0:
      userInput = questionAsked("What will you do?").lower()
      if userInput in go_fight:
        cls()
        printSlime()
        print("You dealt ", (player["ATK"] - enemy["DEF"]) ," damage", sep='')
        enemy["CurHP"] = enemy["CurHP"] - (player["ATK"] - enemy["DEF"])
        if enemy["CurHP"] <= 0:
          print ("You won!")
          input("Press ENTER to go back")
          cls()
          Main()
        else:
          input("Press ENTER to continue")
          cls()
          printSlime()
          print ("[",enemy["name"], ", LV", enemy["level"]," | HP ",enemy["CurHP"], "/",enemy["MaxHP"],"] ", "Fight (f) | Run (r)", sep='')
          print ("-----------------------------------------------")
      elif userInput in go_return:
        cls()
        Main()
        break

def forestScreen():
  playerStatus()
  print ("--------------------[Forest]-------------------")
  print ("|  *      *      **  |  |  * **   **    **    |")
  print ("| * *      *    **   |  |**    **   *    **   |")
  print ("|  *     ***   *    |  |*        *   *     ** |")
  print ("|   *    __________________________  *     ** |")
  print ("|    |  §                          §      *   |")
  print ("|    |_ §   You've encountered a   §      *   |")
  print ("|       §         Monster!         §      **  |")
  print ("|       § Fight(f)        Run(r)   §        * |")
  print ("|       §__________________________§          |")
  print ("| **       *   *    |  |    **                |")
  print ("|   **      | |    |  |   **  ***  ***      **|")
  print ("|     *     |_|   |  |   *      **    *    *  |")
  print ("|_____________________________________________|")
  print ("Fight (f) | Run (r)")
  print ("-----------------------------------------------")
  userInput = questionAsked("What will you do?").lower()
  if userInput in go_fight:
    cls()
    fightScreen()
  elif userInput in go_return: 
    print ('coward')
    cls()
    Main()

def townScreen():
  playerStatus()
  print ("--------------------[Town]---------------------")
  print ("|       +                       **       |*   |")
  print ("|      / \ Church         Home           |    |")
  print ("|     /   \          /////////\           | **|")
  print ("|    /     \    * *  |_____||_|           | * |")
  print ("| l==|°   °|         *             World _|___|")
  print ("| |__|_||__|          *               => _____|")
  print ("|                                         |   |")
  print ("|                           ##             |  |")
  print ("|           Blacksmith    ###               | |")
  print ("|   * *    //////////\  __#                 | |")
  print ("|   *      |         |__||        *         | |")
  print ("|          |_||______|___|         **      | *|")
  print ("|__________________________________________|__|")
  print ("  Info: Player(p) | Stats (s) | Inventory (i)")
  print ("-----------------------------------------------")
  userInput = questionAsked("Where do you want to go?").lower()
  return userInput

# Main executor, menu ------------------
def Main():
  while loop_i > 0:
    if townScreen() in go_world:
      print('Going to world...')
      cls()
      forestScreen()
      break
    elif townScreen() in go_home:
      print('Going home...')
    elif townScreen() in go_church:
      print('Going to church...')
    elif townScreen() in go_blacksmith:
      print('Going to blacksmith...')  
    else:
      print('What?')

# Sequence start-----------------------------------------------------  
while loop_i > 0:
  userInput = questionAsked("Start (Y/N)?").lower()
  if userInput in answer_yes:
    print ("Okay, let's do it")
    break;
  elif userInput in answer_no:
    print ("That's too bad")
    break;
  else:
    print ('What?')
  print("So your answer is " + userInput + ".")
cls()
Main()

1 Ответ

0 голосов
/ 23 ноября 2018

Нам просто нужно взглянуть на следующие строки:

def fightScreen():
  if randomEnemy() == "Goblin":
    enemy = …
  elif randomEnemy() == "Slime":  
    enemy = …
  enemy["level"] = player["level"]

Простой вопрос: что произойдет, если randomEnemy() вернет что-то отличное от "Goblin" или "Slime"?В этом случае enemy не определено.

Или, как этого не может быть, при первом вызове возвращается "Slime", но при втором вызове возвращается "Goblin"?Тогда у вас есть enemy undefined и возникает ваша ошибка.

Простое решение:

def fightScreen():
  enemyName = randomEnemy()
  if enemyName == "Goblin":
    enemy = …
  elif enemyName == "Slime":  
    enemy = …

Или, если это действительно единственные альтернативы:

def fightScreen():
  if randomEnemy() == "Goblin":
    enemy = …
  else:
    enemy = …

Но я бы сделал совершенно иную концепцию: пусть ваши типы врагов будут классами.

Тогда у вас будет что-то вроде

…
class Goblin(object):
    def __init__(self):
        self.name = "Goblin"
        self.level = 1
        self.ATK = 2
        self.DEF = 2
        self.curHP = 5
        self.maxHP = 5

    def print(self):
      print ("--------------------[FIGHT]-------------------")
      print ("|                .                            |")
      print ("|               |                  | .        |")
      print ("|              |                  |//         |")
      print ("|             |  \       /       /  /         |")
      print ("|             |___\     /____  /   /          |")
      print ("|            | \°_\     /°__/ /   /           |")
      print ("|            '               |  /             |")
      print ("|             |   (° °)       -               |")
      print ("|              | _________    |               |")
      print ("|               ||ˇˇˇˇˇˇˇ|   .|               |")
      print ("|               | -------   |                 |")
      print ("|                |_________|                  |")
      print ("|_____________________________________________|")

        …

class Slime(object):
    def __init__(self)
        self.name = "Slime"
        self.level = 1
        self.ATK = 1
        self.DEF = 3
        self.curHP = 5
        self.maxHP = 5
    def print(self):
      print ("--------------------[FIGHT]-------------------")
      print ("|                       ______                |")
      print ("|                ______/      \_              |")
      print ("|              _/               \             |")
      print ("|             /    \     /       \_           |")
      print ("|            /    0       0        \          |")
      print ("|           /                       \         |")
      print ("|           /        ____            |        |")
      print ("|          /                         |        |")
      print ("|          /                          \       |")
      print ("|         /____________________________\      |")
      print ("|                                             |")
      print ("|                                             |")
      print ("|_____________________________________________|")


def randomEnemy():
  monsters = [Goblin, Slime]
  random_enemy = random.choice(monsters)
  return random_enemy() # instantiate the enemy here

# fighting -----------------------
def fightScreen():
  enemy = randomEnemy()
  …

Это намного элегантнее.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...