Python学習【365日チャレンジ!】104日目のマスターU(@Udemy11)です。
【JIN-仁-】の漫画を一気読みして寝不足気味です。
ついつい先が知りたくなり、1巻を読み終えると次の巻に手を出してしまうので、寝る時間がおそくなるんですよね。
漫画が終わると、今度は、TBSオンデマンドをAmazonプライムで一気に観てしまいそうなので、これまた寝不足確定です。
Pythonも学習しないといけないし、ほんと時間がいくらあっても足りません。
それでは今日もPython学習にはいりましょう!
昨日の復習
昨日は、1人目のやり取りについてコードを書いてみました。
2人目以降の処理を考えずに、ただの対話として書いたので、ある程度スムーズにコードを書くことができました。
とはいえ、単純な質問をして、その値をCSVファイルに書き込むだけだったので、基本は、csv
ライブラリとinput
関数を使うだけでした。
今日は、1人目と2人目までに対応したコードになるので少し複雑になってくると思います。
気を引き締めていきましょう!
1つ目の質問

こんにちは。わたしはジャービスです。あなたの名前を教えてください。
1つ目の質問は1人目のときと変わりません。名前を取得して頭文字を大文字にします。
name = input('こんにちは。私はジャービスです。あなたの名前を教えてください。')
c_name = name.title()
CSVファイルの有無を確認
一番最初にこの動作をさせても問題はありませんが、一人目も二人目も最初の質問が同じなので、1つ目の質問が終わってから、ranking.csv
が存在するかどうかの確認を行いました。
import os
check = os.path.exists('ranking.csv')
os
ライブラリをインポートして、os.path.exists()
でranking.csv
ファイルがあるかどうかを確認します。
変数check
にTrue
かFalse
が代入されます。
条件分岐
ranking.csv
ファイルの有無で条件分岐をします。
ranking.csv
ファイルが存在しない場合は一人目の質問と同じ流れになり、ranking.csv
ファイルが存在する場合は、2人目の質問に移ります。
if check is True:
# ranking.csvが存在するときの処理
else:
# ranking.csvが存在しないときの処理
# (一人目の質問と同じ処理)
if
文を使って条件分岐をしました。
1人目の質問については、すでに完成しましたので、昨日書いたコードの内、2つ目の質問以降のコードを書きますが、最後の挨拶のprint
出力のみ、インデントの外側(else
と同じレベル)に記述します。
else:
# ranking.csvが存在しないときの処理
sports = input('\n{}さん、あなたの好きなスポーツは何ですか?\n英語で答えてください\n'.format(c_name))
c_sport = sports.title()
with open('ranking.csv', 'w') as rank_csv:
fieldnames = ('NAME', 'COUNT')
writer = csv.DictWriter(rank_csv, fieldnames=fieldnames)
writer.writeheader()
writer.writerow({'NAME': c_sport, 'COUNT': 1})
print('\n{}さん、回答ありとうございました。\n良い1日をお過ごし下さい!'.format(c_name))
最後のお礼の出力は、ranking.csv
ファイルが存在するときの処理が終わったあとにも出力する必要があるので、インデントのレベルを上げています。
CSVを読み込み
ranking.csv
が存在する場合は、その中身を読み込み、記録されているスポーツ名を抽出します。
with open('ranking.csv', 'r') as rank_r:
ranking = csv.DictReader(rank_r)
for row in ranking:
e_row = row['NAME']
ranking.csv
を読み込みモードで開いて、キーがNAME
に保存されている値を変数e_row
に代入します。
これは、CSVファイルに保存されているデータが1行のみ場合だけを想定しているので、3人目以降の質問を想定する場合はコートの改良が必要です。
今回は、あくまで1行のみ保存されている前提でのコードになります。
2つ目の質問の条件分岐

私のおすすめのスポーツは、Baseballです。
あなたはこのスポーツが好きですか? [Yes/No]
次の質問は、抽出した値を提示して、Yes
かNo
で答えてもらいますが、Y
でもy
でもN
でもn
でも次の質問に移ります。
ただし、それ以外の答えの場合は、次のように質問をやり直します。

Yes か Noで答えてください
私のおすすめのスポーツは、Baseballです。
あなたはこのスポーツが好きですか? [Yes/No]
この質問の条件分岐では、while
ステートメントを利用しました。
while True:
you_like = input('\nわたしがおすすめするスポーツは、{}です。\nあなたはこのスポーツが好きですか?[Yes/No]\n'.format(e_row))
if 'Y' in str.upper(you_like):
break
elif 'N' in str.upper(you_like):
break
else:
print('\nYes か Noで答えてください')
Yes
でもNo
でも次の質問に移るので、どちらでもbreak
でループを抜けます。
ちなみに、どちらも回答をupper()
関数で大文字にして、Y
かN
が含まれていた場合という条件にしています。
他の質問の場合は、Yes か Noで答えてください
と出力したあと、ループに戻るようにしました。
3つ目の質問

Masteruさん、あなたの大好きなスポーツはなんですか?
英語で答えてください。
3つ目の質問は、一人目の質問とほぼ同じですが、「好きなスポーツ」を「大好きなスポーツ」に変更しています。
sports = input('\n{}さん、あなたの大好きなスポーツは何ですか?\n英語で答えてください\n'.format(c_name))
c_sport = sports.title()
コードは一人目の質問のときと同じく、title()
で頭文字を大文字にして変数c_sport
に代入しています。
書き込み用データの整形
次に取得したデータがもともとranking.csv
に保存されていたデータと同じかどうか判断して、同じ場合はCOUNT
に1
を足して、違う場合は行を追加するための準備をします。
rank_r.seek(0)
sport_data = []
for i in ranking:
if i['NAME'] == c_sport:
num_s = i['COUNT']
count_s = int(num_s) + 1
i['COUNT'] = count_s
sport_data.append(i)
check_sport = []
for i in sport_data:
check_sport.append(i['NAME'])
まずは開いていたranking.csv
の読み込み位置を戻すためにrank_r.seek(0)
を入れています。
次に、空のリストsport_data
を作り、CSVファイルから読み込んだデータを代入し、3つ目の質問で受け取ったc_sport
と同じ行のCOUNT
に1
をプラスしています。
DictReader
で読み込んだデータは文字列になっているので、int()
で一旦整数にしたあと1
を足してCOUNT
に戻します。
最後に変数sport_data
にappend()
で行を追加していきます。
これでranking.csv
に書き込むためのデータが変数sport_data
に入ったことになります。
次に変数sport_data
からスポーツ名(NAME
)だけを取り出したリストをcheck_sport
に代入しているコードです。
条件にあったデータを書き込む
上記のリストcheck_sport
の中に、3つ目の質問で入力されたc_sport
がなければ、新しく行を追加し、含まれていれば、上記の変数sport_data
をranking.csv
に書き込みます。
if c_sport not in check_sport:
with open('ranking.csv', 'a') as new_d:
writer = csv.writer(new_d)
writer.writerow([c_sport, 1])
else:
with open('ranking.csv', 'w') as add_d:
fieldnames = ('NAME', 'COUNT')
writer = csv.DictWriter(add_d, fieldnames=fieldnames)
writer.writerows(sport_data)
with
ステートメントの読み込みモードで開いているインデントの中でさらにranking.csv
を追記モード('a'
で開いてもいいのか疑問なのですが、3つ目の質問で答えたスポーツ名(c_sport
が先程用意した変数check_sport
の中に入っていない場合はスポーツ名と1
を追記します。
それ以外の場合(すでにスポーツ名がranking.csv
にある場合)、先程用意した変数sport_data
をranking.csv
に上書きします。
最終のコード
最終的にすべてのコードをまとめると次のようになります。
import os
import csv
name = input('こんにちは。私はジャービスです。あなたの名前を教えてください。\n')
c_name = name.title()
check = os.path.exists('ranking.csv')
if check is True:
with open('ranking.csv', 'r') as rank_r:
ranking = csv.DictReader(rank_r)
for row in ranking:
e_row = row['NAME']
while True:
you_like = input('\nわたしがおすすめするスポーツは、{}です。\nあなたはこのスポーツが好きですか? [Yes/No]\n'.format(e_row))
if 'Y' in str.upper(you_like):
break
elif 'N' in str.upper(you_like):
break
else:
print('\nYes か Noで答えてください')
sports = input('\n{}さん、あなたの大好きなスポーツは何ですか?\n英語で答えてください\n'.format(c_name))
c_sport = sports.title()
rank_r.seek(0)
sport_data = []
for i in ranking:
if i['NAME'] == c_sport:
num_s = i['COUNT']
count_s = int(num_s) + 1
i['COUNT'] = count_s
sport_data.append(i)
check_sport = []
for i in sport_data:
check_sport.append(i['NAME'])
if c_sport not in check_sport:
with open('ranking.csv', 'a') as new_d:
writer = csv.writer(new_d)
writer.writerow([c_sport, 1])
else:
with open('ranking.csv', 'w') as add_d:
fieldnames = ('NAME', 'COUNT')
writer = csv.DictWriter(add_d, fieldnames=fieldnames)
writer.writerows(sport_data)
else:
sports = input('\n{}さん、あなたの好きなスポーツは何ですか?\n英語で答えてください\n'.format(c_name))
c_sport = sports.title()
with open('ranking.csv', 'w') as rank_csv:
fieldnames = ('NAME', 'COUNT')
writer = csv.DictWriter(rank_csv, fieldnames=fieldnames)
writer.writeheader()
writer.writerow({'NAME': c_sport, 'COUNT': 1})
print('\n{}さん、回答ありとうございました。\n良い1日をお過ごし下さい!'.format(c_name))
あくまで1人目、2人目の質問までをカバーしたコードなので、次の3人目の質問をしてしまうと、Javisがおすすめするスポーツがranking.csv
に保存された最後の行のスポーツになってしまいます。
with
ステートメントで開いたファイルの中でさらにwith
ステートメントでファイルを開いてもいいのかという疑問が残るのですが、エラーが起こらないので、とりあえず動いているコードという認識をしておいたほうがいいかもしれません。
やってみることが大切
これまでに学習した内容を活用して、コードを書いていますが、プログラマーの方から見れば、ものすごい効率の悪い汚いコードかもしれません。
ただ、自分が書いたコードを記録に残すことで、あとから見れば「よくあんなコード書いてたな〜」というくらい成長できればいいなと思っているので、恥ずかしながらも汚いコードを公開しています。
もちろん、間違っているところもあるだろうし、もっときれいに短く書くこともできると思います。
Python学習初心者の方には、こんなめちゃくちゃなコードを書いてもいいんだなという気持ちになっていただけると幸いです。
この演習問題は1度きりで終わるのではなく、より見やすい効率的なコードを書けるよう、改良していこうと思っています。
繰り返しより良いコードを求めることでスキルも上がっていくわけなので、やっぱり大切なのは継続することですね。
それでは、明日もGood Python!