irakoma
@irakoma (いら)

Are you sure you want to delete the question?

If your question is resolved, you may close it.

Leaving a resolved question undeleted may help others!

We hope you find it useful!

list index out of range が解消できない

タイピングゲームの結果をスコア降順にcsvファイルへと記録したいです。
実行するとエラーが発生しました。
解決方法を教えて下さい。
2つのファイルのソースコードがあります。
エラーが発生しているのは記事152行目です。

エラー内容

<lambda>
    Ranki.rl = Ranki.rl.sort(reverse=True, key=lambda x:x[2])
                                                        ~^^^
IndexError: list index out of range 

該当するソースコード

import tkinter as tk
from tkinter import messagebox
import sys
import time
import threading
from his import His
from ranki import Ranki


QUESTION = ["tkinter", "geometry", "widgets", "messagebox", "configure", 
            "label", "column", "rowspan", "grid", "init"]

class Application(tk.Frame):
    def __init__(self, master):
        super().__init__(master)
        self.pack()

        master.geometry("300x200")
        master.title("タイピングゲーム!")

        # 問題数インデックス
        self.index = 0

        # 正解数カウント用
        self.correct_cnt = 0

        self.create_widgets()

        # 経過時間スレッドの開始
        t = threading.Thread(target=self.timer)
        t.start()

        # Tkインスタンスに対してキーイベント処理を実装
        self.master.bind("<KeyPress>", self.type_event)
    # ウィジェットの生成と配置
    def create_widgets(self):
        self.q_label = tk.Label(self, text="お題:", font=("",20))
        self.q_label.grid(row=0, column=0)
        self.q_label2 = tk.Label(self, text=QUESTION[self.index], width=10, anchor="w", font=("",20))
        self.q_label2.grid(row=0, column=1)
        self.ans_label = tk.Label(self, text="解答:", font=("",20))
        self.ans_label.grid(row=1, column=0)
        self.ans_label2 = tk.Label(self, text="", width=10, anchor="w", font=("",20))
        self.ans_label2.grid(row=1, column=1)
        self.result_label = tk.Label(self, text="", font=("",20))
        self.result_label.grid(row=2, column=0, columnspan=2)

        # # 時間計測用のラベル
        self.time_label = tk.Label(self, text="", font=("",20))
        self.time_label.grid(row=3, column=0, columnspan=2)

        self.flg2 = True

    # キー入力時のイベント処理
    def type_event(self, event):
        # 入力値がEnterの場合は答え合わせ
        if event.keysym == "Return":
            if self.q_label2["text"] == self.ans_label2["text"]:
                self.result_label.configure(text="正解!", fg="red")
                self.correct_cnt += 1
            else:
                self.result_label.configure(text="残念!", fg="blue")

            # 解答欄をクリア
            self.ans_label2.configure(text="")

            # 次の問題を出題
            self.index += 1
            if self.index == len(QUESTION):
                self.flg = False
                self.q_label2.configure(text="終了!")
                messagebox.showinfo("リザルト", f"あなたのスコアは{self.correct_cnt}/{self.index}問正解です。\nクリアタイムは{self.second}秒です。")
                score_his = self.correct_cnt
                time_his = self.second
                # score_rank = self.correct_cnt
                # time_rank  = self.second                  
                numque = len(QUESTION)
                His.set_csv(self,score_his,time_his,numque)
                Ranki.ranki_score(self)
                sys.exit(0)
            self.q_label2.configure(text=QUESTION[self.index])

        elif event.keysym == "BackSpace":
            text = self.ans_label2["text"]
            self.ans_label2["text"] = text[:-1]

        else:
            # 入力値がEnter以外の場合は文字入力としてラベルに追記する
            self.ans_label2["text"] += event.keysym

    def timer(self):
        self.second = 0
        self.flg = True
        while self.flg:
            self.second += 1
            self.time_label.configure(text=f"経過時間:{self.second}")
            time.sleep(1)

if __name__ == "__main__":
    root = tk.Tk()
    Application(master=root)
    root.mainloop()

と、

from his import His
from file import File
import csv
import os
import datetime
path = os.getcwd()
rankilist = []
class Ranki(His) :
    rl = rankilist
    def __init__(self,score_rank,time_rank) :
        self.score_rank = score_rank
        self.time_rank = time_rank
        
    def ranki_score(self) :
        # 時間求める
        t_delta = datetime.timedelta(hours=9)
        JST = datetime.timezone(t_delta, 'JST')
        now = datetime.datetime.now(JST)
        nowtime = now.date().strftime('%Y/%m/%d')
        # 二重リスト
        Ranki.rl.append([f'[{nowtime},{self.numque}問中,{int(self.score_his)},問{self.time_his}秒]'])
        print(Ranki.rl)
        # 降順に並び替え
        Ranki.rl = Ranki.rl.sort(reverse=True, key=lambda x:x[2])
       
        with open(path + '\\rank1.csv','w',encoding='utf-8',newline='') as file:
            csv.writer(file).writerows(Ranki.rl)
        return True
    

自分で試したこと

クラスの中のリスト?が悪さをしているのかと思い、位置やら名前やらを変えてみましたが解決されず、困っています。

0

2Answer

IndexError: list index out of range がどういった意味のエラーかは調べましたか。
調べてエラーの意味がわかったのなら、何が原因か、どう直せばいいかは自明かと思います。

0Like

Comments

  1. @irakoma

    Questioner

    すみません。言葉足らずでした。エラーの意味やx:x[2]の中の数字など、一通り試した後での質問です。
    エラーの意味が知りたかったのではなく、具体的な解決方法を知りたくての質問です。

  2. 他の方への返答内容からエラーの意味をまったく理解できていないことがわかりました。
    もう一度エラーの意味を調べてください。そして、なぜそのエラーがでているのかをもう一度よく考えてください。

  3. おそらくですが、エラーの意味はだいたい把握されているんだと思います。
    リストに3つ目の要素がないことでエラーになっていることは把握されていても、なぜリストに複数要素を追加できていないのか気づけていないのだと思います…。

  4. どうなんでしょね。

    クラスの中のリスト?が悪さをしているのかと思い、位置やら名前やらを変えてみましたが解決されず、困っています。

    '''
    Ranki.rl.append([f'{nowtime},{self.numque}問中,{int(self.score_his)},問{self.time_his}秒'])
    '''
    のように変えてみたのですが、エラーの内容も変わりありませんでした。

    から本質的な理解ができているとはあんまり思えないですけどね。

    リストに3つ目の要素がないことでエラーになっていることは把握されていても、なぜリストに複数要素を追加できていないのか気づけていないのだと思います…。

    理解したうえでここまで推測ができていると仮定したら、リストの中のリストの長さの確認とか、とりあえずリストを作ってそこに複数回appendしてからメインのlistにappendしてみるとか、やれることはたくさんあってそれらをやっていればおのずと答えにたどり着きそうなものですけどね。
    個人的はエラーの解説文章の文字をただただ眺めて理解したつもりになっているだけだと思っています。

具体的な解決方法を知りたくての質問です。

# 二重リスト
Ranki.rl.append([f'[{nowtime},{self.numque}問中,{int(self.score_his)},問{self.time_his}秒]'])

こちらの記述ですが、リスト風の文字列が1要素だけ追加されている形となっています。
こちらを修正すれば、問題は解決すると思います。

0Like

Comments

  1. @irakoma

    Questioner

    '''
    Ranki.rl.append([f'{nowtime},{self.numque}問中,{int(self.score_his)},問{self.time_his}秒'])
    '''
    のように変えてみたのですが、エラーの内容も変わりありませんでした。
    どこを変えたらよろしいでしょうか?

  2. それだと、カンマ区切りの1つの文字列要素となっていますね。
    要素をカンマで区切るために、カンマはf文字列から出してあげてください。

  3. @irakoma

    Questioner

    '''#Python
    Ranki.rl.append([nowtime,self.numque,'問中',self.score_his,'問',self.time_his,'秒'])
    '''
    のように変えてみました。インデックスエラーはなくなりましたが、
    AttributeError: 'NoneType' object has no attribute 'append'
    のように出てきました。色々調べてみてreturnなど追加してみましたが変化ありません。ご教授いただいてもよろしいでしょうか。

  4. 横からですみませんが,あくまでCSVはデータをファイルに保存するための形式なので,リストにデータを保持する段階でCSV文字列を意識することがないようにすべきです.リストには生データを保持しておき,ファイルに書出す部分はメソッドを分けてそこで文字列を生成してください. これだけでも下手に処理をごちゃごちゃにすることが減ります.
    そもそもの話インスタンスとカプセル化がよく分かってなさそうなクラスの書き方をしてはいるんですが……

  5. Ranki.rl = Ranki.rl.sort(reverse
    

    sortは破壊的メソッド(すなわち元の配列が変更される)かつ返値がNoneなので代入してはいけません.

  6. @irakoma

    Questioner

    様々な訂正ありがとうごっざいます。色々加味して
    '''
    def ranki_score(self) :
    # 時間求める
    t_delta = datetime.timedelta(hours=9)
    JST = datetime.timezone(t_delta, 'JST')
    now = datetime.datetime.now(JST)
    nowtime = now.date().strftime('%Y/%m/%d')
    # 二重リスト
    rl = []
    rl.append([nowtime,self.numque,'問中',self.score_his,'問',self.time_his,'秒'])
    return rl

        # 降順に並び替え
    def ranki_sort(self):
        print(self.rl)
        self.ranki_score()
        self.rl.sort(reverse=True, key=lambda x:x[3])
        self.ranki_file()
        
        # ファイル書き込み
    def ranki_file(self):    
        with open(path + '\\rank1.csv','w',encoding='utf-8',newline='') as file:
            csv.writer(file).writerows(self.rl)
        return True
    
    def read_ranki(self):
        rancon =''
        with open (path + '\\rank1.csv','r', encoding='utf-8') as  file :
            rancon = file.read()
            return rancon
    

    '''
    のように変更しましたが、アトリビュートエラーが消えません。
    何処を変更したらいいでしょうか?

  7. 差し出がましいのですがMarkdownのCode blocksはバッククォート`が3つです.(Windows用日本語キーボードならShift+@)プレビューを確認のうえで投稿をお願いします.

  8. とりあえず目に着くところをあげるならば意味もなくselfを付与しているので問題の切り分けがすごく大変なことです.インスタンス化すべきかそうでないかはよく検討してください.分からないなら下手にクラスを書かないでください.

Your answer might help someone💌