プログラミング入門II
2024.07.03
例外処理

Back to index page



  1. 本日の作業内容

  2. 前回の宿題について

    今回もモジュールの読み込みに関する問題が多く発生しました.モジュール名を 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] 
    

  3. 前回の復習

    モジュールについて学習しました.何度も使用するプログラムのかたまりをモジュールとして別ファイルとして用意しておくことで,本体のソースコードをすっきり短く記述することも可能です.必要に応じて使用していきましょう.

  4. 例外処理

    プログラム自体は正しいものの,実行時に予期されない入力や値がでてきたときにエラーが出る場合があり,それを「例外」と言います.プログラムが実行時にエラーで落ちることを回避し,例えば最低限それまで得られていた値を保存してから終了するなど,事前に対策を行うことを「例外処理」と言います.今回は例外処理の簡単なところを実習で試していきましょう.

  5. 演習

    今回の演習問題です.

  6. 宿題

    いつものようにレポート提出システムを利用します.授業当日の18:00から閲覧可能で,締切りは翌週月曜日の10:00です.

  7. 次回の予習範囲

    次回はいよいよ最後の単元のファイル処理です.教科書のp.354-373の範囲を学習しますので,予習をしてきてください.


目次ページに戻る