プログラミング入門I
2023.12.25
オブジェクトと型

Back to index page



  1. 本日の作業内容

  2. 前回の宿題について

    今回はエラーになるものが無くて安心したのですが,形式的なミスは残念ながら1件でてきました.引き続き,解答用紙の番号と名前の部分には注意を向けてください.

    解答用紙の名前間違い: b2223

    以下は例によって問題のあるプログラムの例です.参考にしてください.

    for _ in range(10):
        
        num1,num2 =sorted(random.sample(range(1,21),2))
        
        print(f"{num1:2d}-{num2:2d}:",end="")
    
        for i in range(1,21):
            
            if num1 <= i <= num2:
                
                print("*  ",end="")
                
            else:
                
                print("   ",end="")
    
        print()
    

    中身もちょっと減点なのですが,それ以前になんで毎回空行を入れるんでしょうか?ソースが間延びして見づらいし,締まりが無いですね.

    for c in range(1,11):
        s=random.randint(1,20)
        e=random.randint(1,20)
        
        if s>e:
            s,e=e,s
        else:
            pass
        
        print(f'{s:2} - {e:2}:',end='')
        for a in range(1,s):
            print('   ',end='')
        for a in range(s,e+1):
            print('  *',end='')
        else:
            print('')
    

    処理は問題ないのですが,変数名はなんとかなりませんか.何を表しているのかわからないし,for 文の変数に i ではなく c とかを使うと何か別の意味があるのかと思ってしまいます.

    for i in range(1,11):
        num1 = random.randint(1,20)
        num2 = random.randint(1,20)
        if num1 > num2:
            num1 , num2 = num2, num1
        else:
            num1 ,num2 = num1, num2
        print(f'{num1:2} - {num2:2}:',end='')
        for j in range(1,num1):
                print(f'   ',end='')
        for k in range(num1,num2+1):
                print('  *',end='')
    

    内側の2つの for 文ですが,変数を分ける必要はありません.両方とも j でなんの問題もありません.

    for _ in range(1, 11):
        a = random.randint(1, 20)
        b = random.randint(1, 20)
        counter = 0
        if a > b:
            a, b = b, a
        print(f'{a:>2} - {b:>2}:',end = ' ')
        for _ in range(1, 21):
            counter += 1
            if a <= counter <= b:
                print(' *',end = ' ')
            else:
                print('  ',end = ' ')
        print()
    

    これまで何度か言及していることですが,教科書に for 文のカウンタ用の変数を使わない下線文字 _ の手法が紹介されているということで,なぜか意地でもカウンタ用の変数 i などを置かないで処理を書こうという人が絶えません.普通に i を使って楽に書けるのに,どうしてわざわざ下線文字にして counter などの変数を置くのでしょうか?

    for j in range(1,12):
    small = random.randint(1,20)
    large = random.randint(1,20)
    if small > large:
        small, large = large, small
    print(f'{small:2} - {large:2}:  ', end = '')
    
    for x in range(1,21):
        if small <= x <= large:
            print('*  ', end = '')
        else:
            print('   ',end = '')
    if x == 20:
        print('\n', end = '')
    

    さて,ここまですでに何件か出ている上のような if 文で処理を書く方法ですが,これには無駄な処理が入っています.一つには if 文自体が負荷をかけていることで,if 文は無いなら無い方が良いこと,もう一つはアスタリスクの出力が終わった後も,空白文字の出力という処理を行うことで,2重に無駄な作業が入っています.これまでにも言っていますが,if 文を使わなくてできる方法についてまずは考えてください.

    count = 1
    
    print('           ', end = '')
    
    for i in range(1,21):
        print(f'{i:3}', end = '')
    else:
        print()
    
    for j in range(1,72):
        print('-', end = '')
    else:
        print()
        
    for k in range(1,11):
        a = random.randint(1,20)
        b = random.randint(1,20)
        if a > b:
            a, b = b, a
        print(f'{a:2} - {b:2}:', end = '')
        print()
        count += 1
        if a <= count <= b:
            print('   *')
        else:
            print('    ')
    

    for 文の変数を i, j, k と変えていますが,それは不要です.多重になったループでなければ,同じ変数のままで,というか,基本的には i で大丈夫です.で,上の問題はそこではなくて,変な変数 count を使っているところで,これがきちんと初期化や代入が行われていないために,出力結果が以下のようになってしまいます.

    1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 18 19 20
    -----------------------------------------------------------------------
     3 - 19:
        
     6 -  7:
        
     3 - 19:
       *
     3 - 17:
       *
     5 - 13:
       *
     9 - 18:
        
     1 - 13:
       *
     2 - 19:
       *
     1 - 13:
       *
     1 - 18:
       *
    

    for i in range(10):
        num1 = random.randint(1,19)
        num2 = random.randint(num1+1,20)
        print(f'{num1:>2} - {num2:>2}:')
    
        for i in range(1, num1-1):
            print('   ', end = '')
        for i in range( num1 , num2 ):
            print('  *')
        else:
            print()
    

    内側の for 文の変数が i で,外側と重複しているので,動作がおかしくなります.

    for _ in range (10):
        num1=random.randint(1,20)
        num2=random.randint(1,20)
        print(f'{num1:2} - {num2:2}:',end='')
        for x in range(1,21):
            if x == num1 or x == num2:
                print(' * ',end='')
            else:
                print('  ',end='')
        else:
            print()       
    

    等価演算子 == では今回の表示はできません.

    for _ in range(10):
        x = random.randint(1, 20)
        y = random.randint(1, 20)
    
        if x > y:
            x, y = y, x
        print(f'{x:2} - {y:2}:', end = '')
    
        for j in range(1, 21):
            if x - 1 < j < y + 1:
                print('  *', end = '')
            else:
                print('   ', end = '')
            print('')
    

    最後の print('') があるために,毎回改行してしまうので,表示が本来のものとは違うことになります.

    for _ in range(1,11):
       num1= random.randint(1,20)
       num2= random.randint(1,20)
    
       if num2 > num1:
          num1 = num2
          num2 = num1
       print(f'{num2:3}-{num1:3}:',end='')
       for _ in range(1,num2):
          print('   ',end='')
       for _ in range(num2,num1+1):
          print('  *',end='')
       else:
          print()
    

    値の入れ替え処理が間違っているので,if 文の式が真のときには変数 num1 と num2 の値が同じになり,以下のように同じ数が立て続けに出るという間違った結果になります.

    1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 18 19 20
    --------------------------------------------------------------------------------
      2-  2:     *
     19- 19:                                                        *
     16- 16:                                               *
     10- 10:                             *
     11- 11:                                *
      4-  4:           *
      7- 18:                    *  *  *  *  *  *  *  *  *  *  *  *
     16- 16:                                               *
     14- 14:                                         *
      1-  7:  *  *  *  *  *  *  *
    
    

    for _ in range(10):
        x=random.randint(1,20)
        y=random.randint(1,20)
        x,y=sorted([x,y])
        print(f'{x:2} - {y:2}:',end='')
        for j in range(1,21):
            if x <= j<= y:
                print(' *',end='')
            else:
                print('  ',end='')
        else:
                print('')
    else:
        print('')
    

    * を表示する print 関数の文字列にスペースが足らないので,以下のように表示がずれます.

    1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 18 19 20
    -------------------------------------------------------------------
    11 - 14:                     * * * *            
     7 -  9:             * * *                      
    11 - 19:                     * * * * * * * * *  
     1 -  6: * * * * * *                            
     5 - 13:         * * * * * * * * *              
     6 - 16:           * * * * * * * * * * *        
     4 - 17:       * * * * * * * * * * * * * *      
     1 -  4: * * * *                                
     9 - 16:                 * * * * * * * *        
     8 - 18:               * * * * * * * * * * *    
    

    for i in range(10):
        num1 = random.randint(1,20)
        num2 = random.randint(1,20)
        if num1 > num2:
            num1, num2 = num2, num1
        print(f'{num1:2} - {num2:2}:',end = '')
        for j in range(num1 * 3 - 1):
            print(' ',end = '')
        else:
            print('',end = '')
            for k in range(num2 - num1 + 1):
                print('*  ',end = '')
            else:
                print()
    

    * 表示の処理を内側の for 文の else に入れたので,3重の for 文になってしまいました.多重の for 文がテーマではありますが,不必要に深い階層にするのは見通しも悪くなるので,あまりお薦めしません.

        if num1 <= num2:
            start_range = num1
            end_range = num2
        else:
            start_range = num2
            end_range = num1
    

    値の入れ替え処理をちゃんと覚えておきましょう.

    a = random.randint(1, 20)
    b = random.randint(1, 20)
    if a > b:
        c = a
        a = b
        b = c
    

    オブジェクト指向ではない古いC言語などでの入れ替え処理です.せっかく Python を使っているのだから,もっとモダンな処理を覚えましょう.

    for _ in range(10):
        small = random.randint(1,20)
        large = random.randint(1,20)
        if small >large:
            small,lage = large,small
        print(f'{small:>2} - {large:>2}:', end = '')
    
        for j in range(small,large + 1):
            print('  *' , end = '' )
        else:
            print()
    

    上のものは2点大きな問題があります.一つ目は値の入れ替え処理で変数名が間違っているので入れ替えではなく上書きになって,同じ数になってしまうことで,もう一つはスペースを入れる処理を書いていないので,* が左揃えになってしまうことです.なので,下のような出力になります.

    1  2  3  4  5  6  7  8  9 10 11 12 13 14 15 16 17 18 19 20
    --------------------------------------------------------------------
    17 - 17:  *
     3 - 15:  *  *  *  *  *  *  *  *  *  *  *  *  *
     2 - 13:  *  *  *  *  *  *  *  *  *  *  *  *
     5 -  5:  *
     1 -  1:  *
    16 - 16:  *
     3 -  3:  *
     2 -  2:  *
    13 - 19:  *  *  *  *  *  *  *
     6 -  6:  *
    

    for i in range(10):
        num1 = random.randint(1,20)
        num2 = random.randint(1,20)
        
        if num1 > num2:
            num1,num2 = num2,num1
            
        if num1 == num2:
            print(f'{num1} - {num2}'.rjust(8, " "),end='')
            for i in range(num1):
                print('   ',end='')
            print('*')
        else:
            print(f'{num1} - {num2}'.rjust(8, " "),end='')
            for i in range(num1):
                print('   ',end='')
            print('*',end='')
            for i in range((num2-num1)-1):
                print('  *',end='')
            print('  *')
    

    変数 num1 と num2 が同じ時に処理は特に用意する必要は無いです.

    print("         1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20")
    

    これはやっちゃダメ!

  3. 前回の復習

    今回は確認テストで復習状況をチェックしますので,しっかり準備してください.

  4. オブジェクトと型

    Python は「オブジェクト指向言語」というプログラミング言語の一つです.その「オブジェクト」の意味がこの章では詳しく説明されています.ただ,この授業で行っているような初歩的なプログラムではその恩恵を受けることはほとんどありませんが,それでも今回はいろいろと確認していきましょう.

    1. オブジェクトとは
    2. 変数に値を代入するという操作はオブジェクトとしての値に変数名を紐づける,ということになります.それが特にわかるようなことはプログラミングの作業中にはありませんが,後ほど出てくるように誰も参照しないオブジェクトは削除する,という裏側の機能によってメモリの無駄遣いを防ぐことにはなっています.

      まずは,教科書 p.116(旧版では p.114)にあるようにインタラクティブシェルで試してみてください.

    3. ミュータブルとイミュータブル
    4. まだリストなどを学習していないので,このミュータブルとイミュータブルの違いを実感することはありません.リストを学習し始めて,変な処理を書いてしまうと,これに関するエラーを目にすることがあるかもしれません.

    5. 同一性判定演算子
    6. == は値が同じかどうかを判定する比較演算子でしたが,is 演算子はオブジェクトそのものが同じかどうかを判定します.

  5. 型と演算
    1. これまでにも型の話は出てきていますが,実際に演算を行うとどうなるのかについて,一応教科書をよく見て確認しておいてください.また,教科書 p.124(旧版では p.122)にある Table 5-3 には様々な組み込み関数が紹介されていますので,ここはぜひとも活用できるように覚えておきましょう.本日の演習問題ではこれらを使うプログラムを作っていきます.また,教科書 p.127(旧版では p.125)の List 5-7 に例示されている数値の表示の際の空白を 0 で埋める表現も,場合によっては使用しますので,確認しておいてください.

    2. ビット演算
    3. どのプログラミング言語の教科書にも出てくるビット演算ですが,入門的な範囲では基本的には使うことはありません.これは複数のフラグを管理するような用途において,通常の演算よりもビット演算の方が高速であるために用意されているものだと思ってください.

      今回はファイルのアクセス許可などで使用されているフラグ判定についての簡単な作業を演習で体験します.一応こんなもんだと思って知識として持っておいてください.

  6. 演習

    今回の演習問題です.

  7. 本日のまとめ

  8. 宿題

    宿題が公開されるのは明日火曜日10:00の予定で,締切りは来年の1月15日の10:00です.レポート提出システムを使用します.

  9. 次回の予習範囲

    次回は教科書のp.134-162(旧版は p.132-159)の範囲を学習しますので,予習をしてきてください.


目次ページに戻る