Ошибка имени в ранее определенном методе класса и IndexError в индексе, который должен существовать - PullRequest
0 голосов
/ 15 января 2020

Итак, я получаю NameError для np c .name (и я предполагаю, что оно возникнет во всех последующих переменных класса, связанных с методами, которые я пытаюсь переопределить), также у меня есть IndexError, возникающий ранее.

Я объясню более подробно, но сначала мой код.

Это мой полный код, будьте осторожны:

# import pickle
import pickle
npcs_pickle_file = 'NPCatt.pk'
npc_count = 200

class NPC:
    def __init__(self, name="", occupation="", weakness="", need="", desire="", enemy="",
                 rumor="", secret="", passion="", redeeming_quality="",damning_quality="", happy="",
                 occ_desire="", occ_complication="", pc_opinion="", accomplishment="", magical_gear="",
                 political_influence="", resource="", intel="", research=""):

        # Attributes
        self.name = name
        self.occupation = occupation
        self.weakness = weakness
        self.need = need
        self.desire = desire
        self.enemy = enemy
        self.rumor = rumor
        self.secret = secret
        self.passion = passion
        self.redeeming_quality = redeeming_quality
        self.damning_quality=damning_quality
        self.happy = happy
        self.occ_desire = occ_desire
        self.occ_complication = occ_complication
        self.pc_opinion = pc_opinion
        self.accomplishment = accomplishment
        self.magical_gear = magical_gear
        self.political_influence = political_influence
        self.resource = resource
        self.intel = intel
        self.research = research


    def __str__(self):
        npc_output = "####NPC SUMMARY####\n"
        for att, val in self.__dict__.items():
            if val:
                npc_output += (f"{att} = {val}\n")
        return npc_output

# open a pickle file
# load your data back to memory when you need it
try:
    with open(npcs_pickle_file, 'rb') as fi:
        npcs = pickle.load(fi)
except FileNotFoundError as fne:
    #file doesnt exist prob first time running so create a dict with the 170 npc id's
    npcs = {id: None for id in range(npc_count)}


#select an NPC to modify / create
npc_id = None
while not npc_id:
    try:
        npc_id = int(input(f"Enter the id number of the NPC you wish to modify: "))
    except ValueError as ve:
        print("You must provide a numerical id")

    if npc_id < 0 or npc_id >= npc_count:
        npc_id = None
        print(f"you must provide a value between 0 and {npc_count}")



if npcs[npc_id]:
    npc = npcs[npc_id]
    print(npc)
    modify = input("This NPC already exists, do you want to continue and change them? (y/n): ")
    if modify.lower() == "y":
        name = input("Enter name of NPC: ") 
        occupation = input("Enter NPC occupation: ")
        weakness= input("Enter Weakness: ")
        need= input("Enter Need: ")
        desire= input("Enter Desire: ")
        enemy= input("Enter Enemy: ")
        rumor= input("Enter Rumor: ")
        secret= input("Enter Secret: ")
        passion= input("Enter Passion: ")
        redeeming_quality=input("Enter Redeeming Quality: ")
        damning_quality=input("Enter Damning Quality: ")
        happy= input("Enter, is this NPC happy?: ")
        occ_desire= input("Enter an Occupational Desire: ")
        occ_complication= input("Enter an Occupational Complication: ")
        pc_opinion= input("Enter this NPC's disposition toward the PCs: ")
        accomplishment= input("Enter an Accomplishment: ")
        magical_gear= input("Enter Magical Gear: ")
        political_influence=input("Enter Political Influence: ")
        resource= input("Enter Resource Level: ")
        intel= input("Enter Intel Tier: ")
        research= input("Enter Research: ")

        npc.name = name
        npc.occupation = occupation
        npc.weakness = weakness
        npc.need = need
        npc.desire= desire
        npc.enemy= enemy
        npc.rumor= rumor
        npc.secret= secret
        npc.passion= passion
        npc.redeeming_quality= redeeming_quality
        npc.damning_quality= damning_quality
        npc.happy= happy
        npc.occ_desire=occ_desire
        npc.occ_complication=occ_complication
        npc.pc_opinion=pc_opinion
        npc.accomplishment=accomplishment
        npc.magical_gear=magical_gear
        npc.political_influence=political_influence
        npc.resource=resource
        npc.intel=intel
        npc.research=research


    else:    

        npcs[npc_id] = NPC(name=npc.name, occupation=npc.occupation,weakness=npc.weakness,need=npc.need,desire=npc.desire,\
                       enemy=npc.enemy,rumor=npc.rumor,secret=npc.secret,passion=npc.passion,redeeming_quality=npc.redeeming_quality,\
                       damning_quality=npc.damning_quality,happy=npc.happy,occ_desire=npc.occ_desire,\
                       occ_complication=npc.occ_complication\
                       ,pc_opinion=npc.pc_opinion,accomplishment=npc.accomplishment,\
                       magical_gear=npc.magical_gear,political_influence=npc.political_influence,resource=npc.resource,\
                       intel=npc.intel,research=npc.research)
else:
    name = input("Enter name of NPC: ") 
    occupation = input("Enter NPC occupation: ")
    weakness= input("Enter Weakness: ")
    need= input("Enter Need: ")
    desire= input("Enter Desire: ")
    enemy= input("Enter Enemy: ")
    rumor= input("Enter Rumor: ")
    secret= input("Enter Secret: ")
    passion= input("Enter Passion: ")
    redeeming_quality=input("Enter Redeeming Quality: ")
    damning_quality=input("Enter Damning Quality: ")
    happy= input("Enter, is this NPC happy?: ")
    occ_desire= input("Enter an Occupational Desire: ")
    occ_complication= input("Enter an Occupational Complication: ")
    pc_opinion= input("Enter this NPC's disposition toward the PCs: ")
    accomplishment= input("Enter an Accomplishment: ")
    magical_gear= input("Enter Magical Gear: ")
    political_influence=input("Enter Political Influence: ")
    resource= input("Enter Resource Level: ")
    intel= input("Enter Intel Tier: ")
    research= input("Enter Research: ")
    npc.name = name
    npc.occupation = occupation
    npc.weakness = weakness
    npc.need = need
    npc.desire= desire
    npc.enemy= enemy
    npc.rumor= rumor
    npc.secret= secret
    npc.passion= passion
    npc.redeeming_quality= redeeming_quality
    npc.damning_quality= damning_quality
    npc.happy= happy
    npc.occ_desire=occ_desire
    npc.occ_complication=occ_complication
    npc.pc_opinion=pc_opinion
    npc.accomplishment=accomplishment
    npc.magical_gear=magical_gear
    npc.political_influence=political_influence
    npc.resource=resource
    npc.intel=intel
    npc.research=research


with open(npcs_pickle_file, 'wb') as fi:
    # dump your data into the file
    pickle.dump(npcs, fi)

Я нуб, так что Структура кода была предоставлена ​​в качестве ответа на мой единственный другой вопрос на сайте. Я расширил его для своих целей.

Дело в том, что NP C, индексированный как [1], отлично сохранен, отображается по мере необходимости и может быть изменен. Но при определении новых NPC я сначала получаю IndexError для новых Indexable NPC, которые я обнаружил с помощью

try: #the code for when the NPC has been previously defined
except IndexError:#the code on the last else block, for new indexes

, чтобы проверить, работал ли остальной код, и NameError возникает в последнем случае. В блоке, где я определяю каждый атрибут как

self.att=att

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

Спасибо, если вы прочитали все до конца, и я извиняюсь. Пожалуйста, помогите, если можете и хотите.

1 Ответ

0 голосов
/ 15 января 2020

Ваша IndexError проблема связана с удалением файла, созданного в предыдущей версии вашего скрипта. Если этот файл содержит ценные данные, просто переименуйте его на данный момент, и как только вы получите сценарий, работающий и достаточно стабильный, будет время написать сценарий миграции, чтобы вернуть ваши старые данные. Иначе, просто бросьте это xD

по отношению к / NameError, это в последнем else блоке: вы пытаетесь установить атрибуты для переменной npc, которая на самом деле не определена на данный момент - это определено только в блоке if:

if npcs[npc_id]:
    npc = npcs[npc_id]
    # way too much code here
else:
    # repeated code here
    # and here's the issue:
    npc.something = something

Вы уже заметили, что «объединение кусков кода без их понимания не всегда работает», что является хорошим началом (по крайней мере, вы знаете, об этом, так что все еще есть надежда xD), теперь вот еще одно просветление для вас: «пытаться понять грязный код трудно». Вот почему хорошая структура кода важна. Кроме того, короткие функции, которые только (или в основном) зависят от своих аргументов, легче понять (и протестировать!), Чем длинные сценарии с большим количеством условных выражений и блоков кода, которые зависят от того, какая переменная (или нет) определена на расстоянии более 20 строк.

Обычно я этого не делаю, но, похоже, в этом случае вам может быть полезно посмотреть, как выглядит прилично структурированный код. Он далек от совершенства и мог бы извлечь выгоду из некоторых улучшений (например, при редактировании существующего np c, позволяющего пользователю указать, какие атрибуты он хочет изменить, вместо того, чтобы просить его перепечатать все), но это ваша работа, а не моя; -)

import pickle

# coding conventions: pseudo-constants should be ALL_UPPER
NPCS_PICKLE_FILE = 'NPCatt.pk'
NPC_COUNT = 200

# coding convention: class names should be CamelCase
class Npc:
    def __init__(self, name="", occupation="", weakness="", need="", desire="", enemy="",
                 rumor="", secret="", passion="", redeeming_quality="",damning_quality="", happy="",
                 occ_desire="", occ_complication="", pc_opinion="", accomplishment="", magical_gear="",
                 political_influence="", resource="", intel="", research=""):

        # Attributes
        self.name = name
        self.occupation = occupation
        self.weakness = weakness
        self.need = need
        self.desire = desire
        self.enemy = enemy
        self.rumor = rumor
        self.secret = secret
        self.passion = passion
        self.redeeming_quality = redeeming_quality
        self.damning_quality = damning_quality
        self.happy = happy
        self.occ_desire = occ_desire
        self.occ_complication = occ_complication
        self.pc_opinion = pc_opinion
        self.accomplishment = accomplishment
        self.magical_gear = magical_gear
        self.political_influence = political_influence
        self.resource = resource
        self.intel = intel
        self.research = research

    def update(self, **values):
        for key, val in values.items():
            # make sure we're only accepted known attributes
            if not hasattr(self, key):
                raise AttributeError("Npc object has no attribute '{}'".format(key))
            setattr(self, key, val)

    def __str__(self):
        # in Python, string concatenation is better done by
        # building a list and joining it afterward
        npc_output = ["####NPC SUMMARY####"] 
        for att, val in self.__dict__.items():
            if val:
                npc_output.append(f"{att} = {val}")
        npc_output.append("") # so we have a last newline
        return "\n".join(npc_output)


class InvalidDataFile(ValueError):
    pass


def load_npcs_from_file():
    with open(NPCS_PICKLE_FILE, 'rb') as fi:
        try:
            npcs = pickle.load(fi)
        except EOFError as e:
            raise InvalidDataFile(
                "looks like {} is empy - expected a dict, got {}".format(NPCS_PICKLE_FILE, e)
            )

    # make sure we don't have incorrect data from
    # the previous version where what was pickled was a list
    if not isinstance(npcs, dict):
        raise InvalidDataFile(
            "looks like {} is obsolete or corrupted - expected a dict, got {}".format(NPCS_PICKLE_FILE, ncps)
    )

    # make sure we ALWAYS have `NPC_COUNT` npcs whatever
    # (ie: in case the pickle didn't have as many entries as expected)
    missing = NPC_COUNT - len(npcs)
    if missing > 0:
        for id in range(NPC_COUNT):
            ncps.setdefault(id, None)
    return npcs

def init_npcs():
    return {id: None for id in range(NPC_COUNT)}

def load_npcs():
    try:
        return load_npcs_from_file()

    except (FileNotFoundError, InvalidDataFile) as e:
        # so you know what's happening...
        print("got {} when trying to load npcs from file - creating a new dataset".format(e))
        return init_npcs()


def save_npcs(npcs):
    with open(NPCS_PICKLE_FILE, 'wb') as fi:
        # dump your data into the file
        pickle.dump(npcs, fi)    


def get_npc_values():
    # factor out common stuff
    # XXX you definitly want to validate user inputs
    values = {}

    values["name"] = input("Enter name of NPC: ") 
    values["occupation"] =  input("Enter NPC occupation: ")
    values["weakness"] =  input("Enter Weakness: ")
    values["need"] =  input("Enter Need: ")
    values["desire"] =  input("Enter Desire: ")
    values["enemy"] =  input("Enter Enemy: ")
    values["rumor"] =  input("Enter Rumor: ")
    values["secret"] =  input("Enter Secret: ")
    values["passion"] =  input("Enter Passion: ")
    values["redeeming_quality"] = input("Enter Redeeming Quality: ")
    values["damning_quality"] = input("Enter Damning Quality: ")
    values["happy"] =  input("Enter, is this NPC happy?: ")
    values["occ_desire"] =  input("Enter an Occupational Desire: ")
    values["occ_complication"] =  input("Enter an Occupational Complication: ")
    values["pc_opinion"] =  input("Enter this NPC's disposition toward the PCs: ")
    values["accomplishment"] =  input("Enter an Accomplishment: ")
    values["magical_gear"] =  input("Enter Magical Gear: ")
    values["political_influence"] = input("Enter Political Influence: ")
    values["resource"] =  input("Enter Resource Level: ")
    values["intel"] =  input("Enter Intel Tier: ")
    values["research"] =  input("Enter Research: ")

    return values

def update_npc(npc):
    new_values = get_npc_values()
    npc.update(**new_values)

def create_npc():
    values = get_npc_values()
    return Npc(**values)

def get_npc_id():
    #select an NPC to modify / create
    npc_id = None
    while npc_id is None:
        try:
            npc_id = int(input(f"Enter the id number of the NPC you wish to modify: "))
        except ValueError as ve:
            print("You must provide a numerical id")

        if npc_id < 0 or npc_id >= NPC_COUNT:
            npc_id = None
            print(f"you must provide a value between 0 and {NPC_COUNT}")

    return npc_id


def edit_npc(npcs):
    npc_id = get_npc_id()

    # this should be safe now... theoretically at least
    npc = npcs[npc_id]


    if npc is None:
        ok = input("This NPC doesn't exist yet, do you want to create it (y/n): ")
        if ok.strip().lower() == 'y':
            npcs[npc_id] = create_npc()
            # let the caller know something was changed
            return True
    else:
        ok = input("This NPC already exists, do you want to continue and change them? (y/n): ")
        if ok.strip().lower() == "y":
            update_npc(npc)
            # let the caller know something was changed
            return True

    # let the caller know nothing was changed
    return False

def show_npcs(npcs):
    for id, npc in npcs.items():
        print("{} : {}".format(id, npc))
    print("") # add a blank line


def get_next_action():
    while True:
        print("what do you want to do ?")
        print("S - show existing npcs")
        print("E - edit a npc")
        print("Q - quit")

        action = input(">> ").strip().upper()
        if action not in "SEQ":
            print("sorry, I don't undertand '{}'".format(action))
        return action



def main():
    npcs = load_npcs()

    while True:
        nb_valids = len([_ for _ in npcs.values() if _])
        print("we have {} valid npcs".format(nb_valids))

        action = get_next_action()

        if action == "Q":
            break

        elif action == "E":
            if edit_npc(npcs):
                print("saving data")
                save_npcs(npcs)

        elif action == "S":
            show_npcs(npcs)




if __name__ == "__main__":
    main()
...