前提・実現したいこと
PyQというプログラミング学習サービスで
for row in f:
if 'good' in path: good_list.append(row)
if 'bad' in path: bad_list.append(row)
上記の処理をリスト内法表記や高階関数を使ったものに書き換えて見たのですが、
good_list, bad_listを参照しようとするとエラーが出てしまいます。
なぜなのか考えて見たのですがさっぱり見当がつきません。
よろしくお願いいたします。
発生している問題・エラーメッセージ
Traceback (most recent call last)
File "/home/appuser/venv/lib/python3.6/site-packages/flask/app.py", line 2309, in __call__
return self.wsgi_app(environ, start_response)
File "/home/appuser/venv/lib/python3.6/site-packages/flask/app.py", line 2295, in wsgi_app
response = self.handle_exception(e)
File "/home/appuser/venv/lib/python3.6/site-packages/flask/app.py", line 1741, in handle_exception
reraise(exc_type, exc_value, tb)
File "/home/appuser/venv/lib/python3.6/site-packages/flask/_compat.py", line 35, in reraise
raise value
File "/home/appuser/venv/lib/python3.6/site-packages/flask/app.py", line 2292, in wsgi_app
response = self.full_dispatch_request()
File "/home/appuser/venv/lib/python3.6/site-packages/flask/app.py", line 1815, in full_dispatch_request
rv = self.handle_user_exception(e)
File "/home/appuser/venv/lib/python3.6/site-packages/flask/app.py", line 1718, in handle_user_exception
reraise(exc_type, exc_value, tb)
File "/home/appuser/venv/lib/python3.6/site-packages/flask/_compat.py", line 35, in reraise
raise value
File "/home/appuser/venv/lib/python3.6/site-packages/flask/app.py", line 1813, in full_dispatch_request
rv = self.dispatch_request()
File "/home/appuser/venv/lib/python3.6/site-packages/flask/app.py", line 1799, in dispatch_request
return self.view_functions[rule.endpoint](**req.view_args)
File "/home/appuser/work/main.py", line 32, in index
fortune['message'] = random.choice(good_list)
File "/usr/lib/python3.6/random.py", line 260, in choice
raise IndexError('Cannot choose from an empty sequence') from None
IndexError: Cannot choose from an empty sequence
該当のソースコード
# 1: 大吉、2: 吉、3: 中吉、4: 小吉、5: 凶、6:大凶
import random
from flask import Flask, render_template, request
app = Flask(__name__)
GOOD_FILE = 'input/fortune_good.txt'
BAD_FILE = 'input/fortune_bad.txt'
@app.route("/")
def index():
good_list = []
bad_list = []
for path in [GOOD_FILE, BAD_FILE]:
with open(path, encoding='utf-8') as f:
#うまく動く
for row in f:
if 'good' in path: good_list.append(row)
if 'bad' in path: bad_list.append(row)
#fortune_list = list(f)
#リスト内法表記 エラー発生
#good_list = [row for row in fortune_list if 'good' in path]
#bad_list = [row for row in fortune_list if 'bad' in path]
#高階関数へ書き換え エラー発生
#good_list = list(filter(lambda x: 'good' in path, fortune_list))
#bad_list = list(filter(lambda x: 'bad' in path, fortune_list))
#うまく動く
#good_list.extend([row for row in fortune_list if 'good' in path])
#bad_list.extend([row for row in fortune_list if 'bad' in path])
fortune = {}
if request.args.get('fortune', ''):
fortune['no'] = random.randint(1, 6)
if fortune['no'] <= 4:
fortune['message'] = random.choice(good_list)
if fortune['no'] >= 5:
fortune['message'] = random.choice(bad_list)
return render_template('index.html', fortune=fortune)
試したこと
補足情報(FW/ツールのバージョンなど)
-
気になる質問をクリップする
クリップした質問は、後からいつでもマイページで確認できます。
またクリップした質問に回答があった際、通知やメールを受け取ることができます。
クリップを取り消します
-
良い質問の評価を上げる
以下のような質問は評価を上げましょう
- 質問内容が明確
- 自分も答えを知りたい
- 質問者以外のユーザにも役立つ
評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。
質問の評価を上げたことを取り消します
-
評価を下げられる数の上限に達しました
評価を下げることができません
- 1日5回まで評価を下げられます
- 1日に1ユーザに対して2回まで評価を下げられます
質問の評価を下げる
teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。
- プログラミングに関係のない質問
- やってほしいことだけを記載した丸投げの質問
- 問題・課題が含まれていない質問
- 意図的に内容が抹消された質問
- 過去に投稿した質問と同じ内容の質問
- 広告と受け取られるような投稿
評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。
質問の評価を下げたことを取り消します
この機能は開放されていません
評価を下げる条件を満たしてません
質問の評価を下げる機能の利用条件
この機能を利用するためには、以下の事項を行う必要があります。
- 質問回答など一定の行動
-
メールアドレスの認証
メールアドレスの認証
-
質問評価に関するヘルプページの閲覧
質問評価に関するヘルプページの閲覧
+1
f.readlines()をlist(f)にしてみるとか。
投稿
-
回答の評価を上げる
以下のような回答は評価を上げましょう
- 正しい回答
- わかりやすい回答
- ためになる回答
評価が高い回答ほどページの上位に表示されます。
-
回答の評価を下げる
下記のような回答は推奨されていません。
- 間違っている回答
- 質問の回答になっていない投稿
- スパムや攻撃的な表現を用いた投稿
評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。
+1
リスト内表記のコードは、こちらでは正常に動作しなかったので、とりあえずそれを修正しておきます。
# リスト内法表記
with open(path, encoding='utf-8') as f:
good_list = [row for row in f if 'good' in path]
f.seek(0) #追加
bad_list = [row for row in f if 'bad' in path]
【追記】
処理時間とかは分かりませんが、こっちの方が気持ち悪くないかも。
# リスト内法表記
with open(path, encoding='utf-8') as f:
rows = list(f) #リスト化
good_list = [row for row in rows if 'good' in path]
bad_list = [row for row in rows if 'bad' in path]
投稿
-
回答の評価を上げる
以下のような回答は評価を上げましょう
- 正しい回答
- わかりやすい回答
- ためになる回答
評価が高い回答ほどページの上位に表示されます。
-
回答の評価を下げる
下記のような回答は推奨されていません。
- 間違っている回答
- 質問の回答になっていない投稿
- スパムや攻撃的な表現を用いた投稿
評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。
+1
fortune['message'] = random.choice(good_list)
というコードを書いていてそれがエラーになっているのに、なぜそれを質問に含めなかったんでしょうか。
最初から原因はこれで、潜在的なバグがここにあります。
https://docs.python.jp/3.6/library/random.html#random.choice
seq が空のときは、 IndexError が送出されます。
と明確に書いてあります。
good_list
が空な状態でここに到達するとエラーになるのです。推測ですが、bad_list
も同様のコードを書いているのではありませんか?
質問のソース、リスト内法表記とコメントされている部分と、高階関数ととコメントされている部分には明確にバグがあってbad_list
が空になります。
そのせいでエラーが発生しました。
(で、これは修正されたと思います)
もう一つ、PyQが準備しているテストデータ群の中か、あるいはランダム生成されるテストデータか、good_list
やbad_list
が空になるようなエッジケースでエラーになっていたのではないでしょうか?
そのようなテストデータをたまたま踏むとエラーになるわけです。
現実にもよくあるエッジケースでだけ失敗するパターンですね。
投稿
-
回答の評価を上げる
以下のような回答は評価を上げましょう
- 正しい回答
- わかりやすい回答
- ためになる回答
評価が高い回答ほどページの上位に表示されます。
-
回答の評価を下げる
下記のような回答は推奨されていません。
- 間違っている回答
- 質問の回答になっていない投稿
- スパムや攻撃的な表現を用いた投稿
評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。
0
インタープリンタで試してみたところ書き換えたコードは問題なく動きました。なので、PyQ固有の問題という結論になりました。
もし何かこういう事じゃないか?というのがあれば教えていただければと思います。ありがとうございました。
投稿
-
回答の評価を上げる
以下のような回答は評価を上げましょう
- 正しい回答
- わかりやすい回答
- ためになる回答
評価が高い回答ほどページの上位に表示されます。
-
回答の評価を下げる
下記のような回答は推奨されていません。
- 間違っている回答
- 質問の回答になっていない投稿
- スパムや攻撃的な表現を用いた投稿
評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。
15分調べてもわからないことは、teratailで質問しよう!
- ただいまの回答率 88.33%
- 質問をまとめることで、思考を整理して素早く解決
- テンプレート機能で、簡単に質問をまとめられる
質問への追記・修正、ベストアンサー選択の依頼
quickquip
2018/09/07 15:44 編集
ipythonを使ってませんか? ←すみません、勘違いでした。お気になさらずに
hello0130
2018/09/07 15:55
返信ありがとうございます。ipythonは使っていないのですが、PyQというプログラミング学習サービス上で発生しています。あまり関係ないと思っていましたが、書き換え方に問題がないのであればPyQ固有の問題なのかもしれません。
fuzzball
2018/09/07 16:16
randomが吐いている例外のようなので、質問のコードは関係ないのでは?(正しく動くかどうかは別にして) テストデータ生成にrandom使ってるとか。
hello0130
2018/09/07 17:06
回答ありがとうございます。コードを変更するとエラーがでるのでそこが原因だと考えました。エラーメッセージの内容はlistが空だと言っていると理解していますがあっているのでしょうか?エラーメッセージをいまいち理解できていません。エラーコード全文を追記させていただきましたので見ていただけたらと思います。
fuzzball
2018/09/07 17:10
このエラーってリスト内法表記だけじゃないですか?高階関数でも出ます?
hello0130
2018/09/07 17:30
返信ありがとうございます。PyQには判定ボタンがありコードをテストして確認しているようです。高階関数の場合はたまに合格判定になり、リスト内法表記だと何回押しても合格判定にはなりません。どういうことでしょうか?
quickquip
2018/09/07 21:23
fortune['message'] = random.choice(good_list) は自分で書いたコードですか? 書いてないコードですか?
hello0130
2018/09/07 21:59
返信ありがとうございます。その部分は自分で書いた部分です。その部分に適当なリストを入れてみたところエラーが出なくなったのでgood_list自体に問題があるのではと考えています。