プログラミング入門II
2024.07.03
例外処理
今回もモジュールの読み込みに関する問題が多く発生しました.モジュール名を b23** のように教室用のアカウントに指定したのですが,そうなっていないので,読み込めないプログラムがたくさん出ました. モジュール名エラー:モジュール名に _ が付いた b23**_ : b2318 b2328 b2337 b2357 モジュール名エラー:余分なものが付いていた b2322a b2359No2 モジュール名エラー:モジュール名が学生番号 b2342 モジュール名エラー:?? 2024-0626-0626-b2312-2024-07-02_09_34_28 本体のモジュールのアップロードが逆: b2338 モジュールなし: b2321 その他のエラー: b2336 本体用解答用紙不使用: b2355 モジュール用解答用紙不使用: b2270 b2306 b2324 モジュール用解答用紙の番号と名前の間違い: b1923 b2206 b2321 出力時番号間違い: b2309 b2327 以下は例によって問題のあるプログラムの例です.参考にしてください.
head = [sum(ri(0,1) for _ in range(100)) for _ in range(884)]
課題はコインの表の枚数ではなかったし,884回などという微妙な数の反復も意味が分かりません.
ちなみに,英語ではコインの表を head,裏を tail と言います.
freq = [len(list(filter(lambda n: n == i, head))) for i in range(11)] |
他にもコインの表の枚数から離れられない人がいました.
def graph(lst): print('\nRandom numbers: 1-10 11-20 21-30 31-40 41-50 51-60 61-70 71-80 81-90 91-100') print('Frequency: ', end = '') for i in range(10): print(f'{lst[i]+1:5.0f} ', end = '') print('\n\nHistogram of random numbers') print('\n 0 100 200 300 400') print('------------------------------------------------') new_lst = [_ // 10 for _ in lst] for j in range(10): print(f'{(j+1)*10-9:2.0f}-{(j+1)*10:3.0f}|', end = '') for _ in range(new_lst[j]): print('*', end = '') print(f' --{lst[j]:3.0f}') |
反復処理で表示を行うべきところを,自分で手で入力しているところはいただけません.それに加えて,せっかく頻度を数えたのに,数値として表示する部分とグラフの * の横に表示する部分で値が違っているので,おかしいことになっています.
Random numbers: 1-10 11-20 21-30 31-40 41-50 51-60 61-70 71-80 81-90 91-100 Frequency: 1 2 24 149 351 344 112 23 3 1 Histogram of random numbers 0 100 200 300 400 ------------------------------------------------ 1- 10| -- 0 11- 20| -- 1 21- 30|** -- 23 31- 40|************** --148 41- 50|*********************************** --350 51- 60|********************************** --343 61- 70|*********** --111 71- 80|** -- 22 81- 90| -- 2 91-100| -- 0 |
head = [sum(ri(0, 1) for _ in range(10)) for _ in range(100)] |
やっぱりコインの裏表から離れられない人がいて,当然結果もよくわからないことに.
Random numbers: 1-10 11-20 21-30 31-40 41-50 51-60 61-70 71-80 81-90 91-100 Frequency: 0 1 4 11 20 30 20 10 3 1 Histogram of random numbers 0 100 200 300 400 ------------------------------------------------ 1- 10|* -- 1 11- 20|**** -- 4 21- 30|*********** -- 11 31- 40|******************** -- 20 41- 50|****************************** -- 30 51- 60|******************** -- 20 61- 70|********** -- 10 71- 80|*** -- 3 81- 90|* -- 1 91-100| -- 0 |
ranges = [(1, 10), (11, 20), (21, 30), (31, 40), (41, 50), (51, 60), (61, 70), (71, 80), (81, 90), (91, 100)] |
自分で用意しちゃだめです.反復処理を活用しましょう.
def graph(lst): print('\nHistogram of random numbers') print('\n ', end = '') print(' ', end ='') for i in range(0, 401, 100): print(f'{i:<10}', end = '') else: print() for _ in range(50): print('-', end = '') else: print() |
上のソースはこれでモジュールの全てとなっていて,肝心の * を表示させる部分がありません.
def generate_random_numbers(n): return [random.randint(1, 100) for _ in range(n)] |
一様分布の乱数を発生させているので,当然下のような結果になりますよね.
Random numbers: 1-10 11-20 21-30 31-40 41-50 51-60 61-70 71-80 81-90 91-100 Frequency: 104 96 102 107 100 113 83 105 99 91 Histogram of random numbers 0 100 200 300 400 ------------------------------------------------ 1- 10|********** -- 104 11- 20|********* -- 96 21- 30|********** -- 102 31- 40|********** -- 107 41- 50|********** -- 100 51- 60|*********** -- 113 61- 70|******** -- 83 71- 80|********** -- 105 81- 90|********* -- 99 91-100|********* -- 91 |
for i in range(10): print(f'{(i+1)*10-9}-{(i+1)*10}',end='') else: print() |
print 関数の引数の中にスペース(空白文字)が無いので,表示は下のようにつながってわからなくなります.
Random numbers: 1-1011-2021-3031-4041-5051-6061-7071-8081-9091-100 Frequency: 0 3 22 133 352 348 127 15 0 0 |
print(f'{graph(freq)}') |
def graph(lst): print('\nHistogram of random numbers') print('\n ', end = '') for i in range(0, 401, 100): print(f'{i:<10}', end = '') else: print() for _ in range(49): print('-', end = '') else: print() for i in range(0, 10): print(f'{i * 10 + 1:2}-{i * 10 + 10:3}|', end = '') for j in range(1, lst[i] // 10 + 1): print('*', end = '') else: print(f' --{lst[i]:3}') |
下のモジュールは画面に表示させるものなのに,上の本体での呼び出しが print 関数の中に入っているので,最後に None が表示されるという変なことになっています.
その現象を理解するために下のソースを見てみましょう.
a = 1 print(a) print(print(a)) |
上の例では,print 関数の中に print 関数による値の表示を入れています.
1 1 None |
一つ目の普通の print で値 1 が表示され,次の print 関数は print(a) を出力することになり,Python の内部処理の詳細は不明ですが,最後に None が出力されてしまいます.
print('Number of head:',end='') for i in range(10): print(f'[i*10+1:2]-[i*10+10]',end=' ') |
上のソースの最後の print ですが,f 文字列ではあるものの,{ } による表示させる値の指定がなく,全部が文字列として評価されるので,下のような画面表示になってしまいます.
Number of head:[i*10+1:2]-[i*10+10] [i*10+1:2]-[i*10+10] [i*10+1:2]-[i*10+10] [i*10+1:2]-[i*10+10] [i*10+1:2]-[i*10+10] [i*10+1:2]-[i*10+10] [i*10+1:2]-[i*10+10] [i*10+1:2]-[i*10+10] [i*10+1:2]-[i*10+10] [i*10+1:2]-[i*10+10] |
モジュールについて学習しました.何度も使用するプログラムのかたまりをモジュールとして別ファイルとして用意しておくことで,本体のソースコードをすっきり短く記述することも可能です.必要に応じて使用していきましょう.
プログラム自体は正しいものの,実行時に予期されない入力や値がでてきたときにエラーが出る場合があり,それを「例外」と言います.プログラムが実行時にエラーで落ちることを回避し,例えば最低限それまで得られていた値を保存してから終了するなど,事前に対策を行うことを「例外処理」と言います.今回は例外処理の簡単なところを実習で試していきましょう.
今回の演習問題です.
いつものようにレポート提出システムを利用します.授業当日の18:00から閲覧可能で,締切りは翌週月曜日の10:00です.
次回はいよいよ最後の単元のファイル処理です.教科書のp.354-373の範囲を学習しますので,予習をしてきてください.