首页 > 解决方案 > 错误索引错误加载文件配置

问题描述

我的类配置中有一个函数来加载配置文本文件。在加载数据之前,该功能会检查文件以避免用户手动修改文件时出现故障。

def load_config(self):
    list_dat = []
    list_str = []
    with open(self.path, "r") as file:
        for conf in file:
            conf = conf.replace(": ", "|")
            conf = conf.replace("\n", "")
            try:
                conf1, conf2 = conf.split("|")
            except ValueError:
                self.new_config()
                break
            try:
                conf2 = ast.literal_eval(conf2)
            except (ValueError, SyntaxError):
                self.new_config()
                break
            if isinstance(conf2, tuple):
                self.new_config()
                break
            list_str.append(conf1)
            list_dat.append(conf2)

    for x in range(0, len(list_str)):
        if list_str[x] != self.conf_str[x]:
            self.change_config(list_str[x], self.conf_str[x], x, text=True)
            list_str[x] = self.conf_str[x]

    for y in range(0, len(list_dat)):
        if type(list_dat[y]) != type(self.list_default[y]):
            self.change_config(list_dat[y], self.list_default[y], y)
            list_dat[y] = self.list_default[y]

    if len(list_dat) == 0 and len(list_str) == 0:
        self.new_config()

    app = wx.App(False)
    width, height = wx.GetDisplaySize()

    if list_dat[1] != width:
        if list_dat[1] == self.list_default[1]:
            if list_dat[0] == False:
                self.change_config(list_dat[1], width, 1)
                self.change_config(list_dat[2], height, 2)
                list_dat[1] = width
                list_dat[2] = height
        else:
            self.change_config(list_dat[1], width, 1)
            self.change_config(list_dat[2], height, 2)
            list_dat[1] = width
            list_dat[2] = height
    if list_dat[2] != height:
        if list_dat[2] == self.list_default[2]:
            if list_dat[0] == False:
                self.change_config(list_dat[1], width, 1)
                self.change_config(list_dat[2], height, 2)
                list_dat[1] = width
                list_dat[2] = height
        else:
            self.change_config(list_dat[1], width, 1)
            self.change_config(list_dat[2], height, 2)
            list_dat[1] = width
            list_dat[2] = height
    if list_dat[4] > 100:
        self.change_config(list_dat[4], 100, 4)
        list_dat[4] = 100
    else:
        if list_dat[4] < 0:
            self.change_config(list_dat[4], 0, 4)
            list_dat[4] = 0
    if list_dat[5] > 100:
        self.change_config(list_dat[5], 100, 5)
        list_dat[5] = 100
    else:
        if list_dat[5] < 0:
            self.change_config(list_dat[5], 0, 5)
            list_dat[5] = 0
    if list_dat[6] > 100:
        self.change_config(list_dat[6], 100, 6)
        list_dat[6] = 100
    else:
        if list_dat[6] < 0:
            self.change_config(list_dat[6], 0, 6)
            list_dat[6] = 0
    if list_dat[7] > 100:
        self.change_config(list_dat[7], 100, 7)
        list_dat[7] = 100
    else:
        if list_dat[7] < 0:
            self.change_config(list_dat[7], 0, 7)
            list_dat[7] = 0
    if list_dat[8] > 100:
        self.change_config(list_dat[8], 100, 8)
        list_dat[8] = 100
    else:
        if list_dat[8] < 0:
            self.change_config(list_dat[8], 0, 8)
            list_dat[8] = 0

    self.main.id[20], self.main.id[9] = list_dat[0], list_dat[3]
    self.main.id[4], self.main.id[5] = list_dat[1], list_dat[2]
    self.main.id[11], self.main.id[13], self.main.id[15], self.main.id[17], self.main.id[19] = list_dat[4], list_dat[5], list_dat[6], list_dat[7], list_dat[8]


def change_config(self, old, new, n, text=False):
    with open(self.path, "r") as file:
        temp = file.readlines()
        if text:
            temp1, temp2 = temp[n].split(": ")
            temp1 = temp1.replace(str(old), str(new))
            temp[n] = temp1 + ": " + temp2
        else:
            temp[n] = temp[n].replace(str(old), str(new))
    with open(self.path, "w") as file:
        file.writelines(temp)

相反,这是配置文件:

Display Set: True
Display Width: 1024
Display Height: 576
Fullscreen: False
Music Volume: 50
Sound Volume: 50
Voice Volume: 50
Ambient Volume: 50
Other Volume: 50

现在,我遇到了一个错误,老实说,我无法理解是什么原因造成的。如果我以这种方式更改文件,例如:

Display Set: True
Display Width: gfgfdd
Display Height: 576
Fullscreen: False
Music Volume: 50
Sound Volume: 50
Voice Volume: 50
Ambient Volume: 50
Other Volume: 50

我得到错误:

if list_dat[4] > 100:
IndexError: list index out of range

Display Height如果我更改, Music Volume, Sound Volume,和Voice Volume,也会发生同样的事情。Ambient VolumeOther Volume

得到错误后,我去查看配置文件,发现它已被正确纠正。这就是为什么我不明白为什么我不断收到这些错误。

不断给我错误的块是:

if list_dat[1] != width:
    if list_dat[1] == self.list_default[1]:
        if list_dat[0] == False:
            self.change_config(list_dat[1], width, 1)
            self.change_config(list_dat[2], height, 2)
            list_dat[1] = width
            list_dat[2] = height
    else:
        self.change_config(list_dat[1], width, 1)
        self.change_config(list_dat[2], height, 2)
        list_dat[1] = width
        list_dat[2] = height
if list_dat[2] != height:
    if list_dat[2] == self.list_default[2]:
        if list_dat[0] == False:
            self.change_config(list_dat[1], width, 1)
            self.change_config(list_dat[2], height, 2)
            list_dat[1] = width
            list_dat[2] = height
    else:
        self.change_config(list_dat[1], width, 1)
        self.change_config(list_dat[2], height, 2)
        list_dat[1] = width
        list_dat[2] = height
if list_dat[4] > 100:
    self.change_config(list_dat[4], 100, 4)
    list_dat[4] = 100
else:
    if list_dat[4] < 0:
        self.change_config(list_dat[4], 0, 4)
        list_dat[4] = 0
if list_dat[5] > 100:
    self.change_config(list_dat[5], 100, 5)
    list_dat[5] = 100
else:
    if list_dat[5] < 0:
        self.change_config(list_dat[5], 0, 5)
        list_dat[5] = 0
if list_dat[6] > 100:
    self.change_config(list_dat[6], 100, 6)
    list_dat[6] = 100
else:
    if list_dat[6] < 0:
        self.change_config(list_dat[6], 0, 6)
        list_dat[6] = 0
if list_dat[7] > 100:
    self.change_config(list_dat[7], 100, 7)
    list_dat[7] = 100
else:
    if list_dat[7] < 0:
        self.change_config(list_dat[7], 0, 7)
        list_dat[7] = 0
if list_dat[8] > 100:
    self.change_config(list_dat[8], 100, 8)
    list_dat[8] = 100
else:
    if list_dat[8] < 0:
        self.change_config(list_dat[8], 0, 8)
        list_dat[8] = 0

你能帮我么?

编辑:

我添加了一个简化的类版本,只有错误所需的功能。

import ast, os, wx
from pathlib import Path

class config_lib():

    def __init__(self):
        # IdDataDefaultConfig
        self.id1 = True  # SetDisplayDefault
        self.id2 = 1024  # DisplayWidthDefault
        self.id3 = 576  # DisplayHeightDefault
        self.id4 = 1024  # DisplayWidthUser
        self.id5 = 576  # DisplayHeightUser
        self.id6 = 0  # LocationDisplayX
        self.id7 = 50  # LocationDisplayY
        self.id8 = False  # FullscreenDefault
        self.id9 = False  # FullscreenUser
        self.id10 = 50  # MusicVolumeDefault
        self.id11 = 50  # MusicVolumeUser
        self.id12 = 50  # SoundVolumeDefault
        self.id13 = 50  # SoundVolumeUser
        self.id14 = 50  # VoiceVolumeDefault
        self.id15 = 50  # VoiceVolumeUser
        self.id16 = 50  # AmbientVolumeDefault
        self.id17 = 50  # AmbientVolumeUser
        self.id18 = 50  # OtherAudioVolumeDefault
        self.id19 = 50  # OtherAudioVolumeUser
        self.id20 = True  # SetDisplayUser

        self.conf_str = ["Display Set", "Display Width", "Display Height", "Fullscreen", "Music Volume", "Sound Volume", "Voice Volume", "Ambient Volume", "Other Volume"]
        self.list_default = [self.id1, self.id2, self.id3, self.id8, self.id10, self.id12, self.id14, self.id16, self.id18]

        self.path = os.path.join("dat.bw3")
        self.conf = Path(self.path)
        try:
            lc = self.conf.resolve()
        except FileNotFoundError:
            self.new_config()
        else:
            self.load_config()

    def new_config(self):
        list_dat = [[self.conf_str[0], self.id1], [self.conf_str[1], self.id2], [self.conf_str[2], self.id3], [self.conf_str[3], self.id8], [self.conf_str[4], self.id10], [self.conf_str[5], self.id12], [self.conf_str[6], self.id14], [self.conf_str[7], self.id16], [self.conf_str[8], self.id18]]
        with open(self.path, "wt") as file:
            for conf in list_dat:
                print(conf[0], conf[1], sep=': ', file=file)
        self.load_config()

    def load_config(self):
        list_dat = []
        list_str = []
        with open(self.path, "r") as file:
            for conf in file:
                conf = conf.replace(": ", "|")
                conf = conf.replace("\n", "")
                try:
                    conf1, conf2 = conf.split("|")
                except ValueError:
                    self.new_config()
                    break
                try:
                    conf2 = ast.literal_eval(conf2)
                except (ValueError, SyntaxError):
                    self.new_config()
                    break
                if isinstance(conf2, tuple):
                    self.new_config()
                    break
                list_str.append(conf1)
                list_dat.append(conf2)

        for x in range(0, len(list_str)):
            if list_str[x] != self.conf_str[x]:
                self.change_config(list_str[x], self.conf_str[x], x, text=True)
                list_str[x] = self.conf_str[x]

        for y in range(0, len(list_dat)):
            if type(list_dat[y]) != type(self.list_default[y]):
                self.change_config(list_dat[y], self.list_default[y], y)
                list_dat[y] = self.list_default[y]

        if len(list_dat) == 0 and len(list_str) == 0:
            self.new_config()

        app = wx.App(False)
        width, height = wx.GetDisplaySize()

        if list_dat[1] != width:
            if list_dat[1] == self.list_default[1]:
                if list_dat[0] == False:
                    self.change_config(list_dat[1], width, 1)
                    self.change_config(list_dat[2], height, 2)
                    list_dat[1] = width
                    list_dat[2] = height
            else:
                self.change_config(list_dat[1], width, 1)
                self.change_config(list_dat[2], height, 2)
                list_dat[1] = width
                list_dat[2] = height
        if list_dat[2] != height:
            if list_dat[2] == self.list_default[2]:
                if list_dat[0] == False:
                    self.change_config(list_dat[1], width, 1)
                    self.change_config(list_dat[2], height, 2)
                    list_dat[1] = width
                    list_dat[2] = height
            else:
                self.change_config(list_dat[1], width, 1)
                self.change_config(list_dat[2], height, 2)
                list_dat[1] = width
                list_dat[2] = height
        if list_dat[4] > 100:
            self.change_config(list_dat[4], 100, 4)
            list_dat[4] = 100
        else:
            if list_dat[4] < 0:
                self.change_config(list_dat[4], 0, 4)
                list_dat[4] = 0
        if list_dat[5] > 100:
            self.change_config(list_dat[5], 100, 5)
            list_dat[5] = 100
        else:
            if list_dat[5] < 0:
                self.change_config(list_dat[5], 0, 5)
                list_dat[5] = 0
        if list_dat[6] > 100:
            self.change_config(list_dat[6], 100, 6)
            list_dat[6] = 100
        else:
            if list_dat[6] < 0:
                self.change_config(list_dat[6], 0, 6)
                list_dat[6] = 0
        if list_dat[7] > 100:
            self.change_config(list_dat[7], 100, 7)
            list_dat[7] = 100
        else:
            if list_dat[7] < 0:
                self.change_config(list_dat[7], 0, 7)
                list_dat[7] = 0
        if list_dat[8] > 100:
            self.change_config(list_dat[8], 100, 8)
            list_dat[8] = 100
        else:
            if list_dat[8] < 0:
                self.change_config(list_dat[8], 0, 8)
                list_dat[8] = 0

        self.id20, self.id9 = list_dat[0], list_dat[3]
        self.id4, self.id5 = list_dat[1], list_dat[2]
        self.id11, self.id13, self.id15, self.id17, self.id19 = list_dat[4], list_dat[5], list_dat[6], list_dat[7], list_dat[8]

    def change_config(self, old, new, n, text=False):
        with open(self.path, "r") as file:
            temp = file.readlines()
            if text:
                temp1, temp2 = temp[n].split(": ")
                temp1 = temp1.replace(str(old), str(new))
                temp[n] = temp1 + ": " + temp2
            else:
                temp[n] = temp[n].replace(str(old), str(new))
        with open(self.path, "w") as file:
            file.writelines(temp)

conf = config_lib()

编辑2:

__init__类中,它检查文件是否存在。如果不存在,则调用该函数,该new_config()函数使用默认数据创建一个新文件,然后调用该load_config()函数。如果文件存在,load_config()则直接调用该函数。

load_config()函数必须在将文件数据加载到程序之前对其进行检查。

函数的第一个块load_config()

首先要做的是将文件中写入的内容转换为程序可以处理的内容。然后读取文件,将每一行替换为 (":") 后面的有用符号 ("|"),并删除回车符。现在我们必须把它分成两部分,这样一边是数据的名称,而另一边是数据本身。这是通过划分先前插入符号(“|”)的位置来完成的。这种划分是在 中完成的try,因此如果文件内部有一些错误,则通过使用new_config(). 第二件事是将数据(当前是字符串)转换为有效数据。这是由ast.literal_eval(). 再一次,一切都被放入一个try, 原因和之前一样。最后,检查数据是单一的而不是元组。数据名称和数据分别输入list_datlist_str

函数的第二个块load_config()

首先要做的是检查,一个默认的名称列表,如果数据的名称是正确的,如果是错误的,则更正。数据相同,但在这种情况下,检查类型是否与其默认对应项相同。很少(例如 100 个中的 1 个),我注意到如果文件为空,则不会Exceptsplit()块或ast.literal_eval()块中引发 no。所以我补充说:

if len(list_dat) == 0 and len(list_str) == 0:
            self.new_config()

为了避免这个问题。

函数的第三块load_config()(这是给我问题的块):

这将检查屏幕的宽度和高度是否与数据的相同。如果它们不相等,则检查数据是否与默认值(1024、576)相同。如果相同,最后检查默认加载方式是否为false。执行此检查是为了在创建程序屏幕时不会出现任何问题。如果这些检查中的任何一个失败(否则),宽度和高度数据将更改为默认数据。

if list_dat[1] != width:
    if list_dat[1] == self.list_default[1]:
        if list_dat[0] == False:
            self.change_config(list_dat[1], width, 1)
            self.change_config(list_dat[2], height, 2)
            list_dat[1] = width
            list_dat[2] = height
    else:
        self.change_config(list_dat[1], width, 1)
        self.change_config(list_dat[2], height, 2)
        list_dat[1] = width
        list_dat[2] = height
if list_dat[2] != height:
    if list_dat[2] == self.list_default[2]:
        if list_dat[0] == False:
            self.change_config(list_dat[1], width, 1)
            self.change_config(list_dat[2], height, 2)
            list_dat[1] = width
            list_dat[2] = height
    else:
        self.change_config(list_dat[1], width, 1)
        self.change_config(list_dat[2], height, 2)
        list_dat[1] = width
        list_dat[2] = height

类似地,进行同样的音量控制,唯一的区别是数字不大于100(最大音量)或小于0(最小音量)。

if list_dat[4] > 100:
    self.change_config(list_dat[4], 100, 4)
    list_dat[4] = 100
else:
    if list_dat[4] < 0:
        self.change_config(list_dat[4], 0, 4)
        list_dat[4] = 0
if list_dat[5] > 100:
    self.change_config(list_dat[5], 100, 5)
    list_dat[5] = 100
else:
    if list_dat[5] < 0:
        self.change_config(list_dat[5], 0, 5)
        list_dat[5] = 0
if list_dat[6] > 100:
    self.change_config(list_dat[6], 100, 6)
    list_dat[6] = 100
else:
    if list_dat[6] < 0:
        self.change_config(list_dat[6], 0, 6)
        list_dat[6] = 0
if list_dat[7] > 100:
    self.change_config(list_dat[7], 100, 7)
    list_dat[7] = 100
else:
    if list_dat[7] < 0:
        self.change_config(list_dat[7], 0, 7)
        list_dat[7] = 0
if list_dat[8] > 100:
    self.change_config(list_dat[8], 100, 8)
    list_dat[8] = 100
else:
    if list_dat[8] < 0:
        self.change_config(list_dat[8], 0, 8)
        list_dat[8] = 0

函数的第四块load_config()

受控数据分配给它们的变量,以供程序使用。

编辑3:

不幸的是,我之前忘了说些什么。我知道在 上引发了异常ast.literal_eval(),这就是我将其放入的原因try。发生这种情况时,将new_config()调用该函数并且循环应该重新开始。所以列表返回空并由支票再次填充。至少理论上是这样。取而代之的是,虽然文件被创建为应有的新文件(使用默认数据),但函数的其余部分在第二次执行时会分解。也因为,同样,错误只是由我输入的数据引起的。对于其他具有布尔值且在第三块中没有控制的其他(全屏等),不会发生此问题。

标签: pythonpython-3.xpython-3.4

解决方案


将您的脚本简化为这样的内容后,

import ast
with open(self.path, "r") as file:
    for conf in file:
        conf = conf.replace(": ", "|")
        conf = conf.replace("\n", "")
        conf1, conf2 = conf.split("|")
        conf2 = ast.literal_eval(conf2)
        print(conf2)

很明显 ast.literal_eval() 方法会抛出 ValueError 异常:

Traceback (most recent call last):
  File "/usr/local/Cellar/python3/3.6.3/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/IPython/core/interactiveshell.py", line 2910, in run_code
    exec(code_obj, self.user_global_ns, self.user_ns)
  File "<ipython-input-214-f993e6585bcd>", line 7, in <module>
    conf2 = ast.literal_eval(conf2)
  File "/usr/local/Cellar/python3/3.6.3/Frameworks/Python.framework/Versions/3.6/lib/python3.6/ast.py", line 85, in literal_eval
    return _convert(node_or_string)
  File "/usr/local/Cellar/python3/3.6.3/Frameworks/Python.framework/Versions/3.6/lib/python3.6/ast.py", line 84, in _convert
    raise ValueError('malformed node or string: ' + repr(node))
ValueError: malformed node or string: <_ast.Name object at 0x111f50f28>

既然你在这里处理它:

    try:
        conf2 = ast.literal_eval(conf2)
    except (ValueError, SyntaxError):
        self.new_config()
        break

您获得的配置条目比预期的要少,因此会InvalidIndex出错。

现在ast.literal_eval()抛出异常,因为您的输入无法评估为任何已知的 python 类型或方法。

请查看文档以了解如何正确使用它


推荐阅读