Python演習ドリル200 基礎練習51〜60

Pythonプログラムを学び始めた方向けの演習ドリルです。

今回は、基礎練習の51〜60です。

jupyterとjupyter notebook

本演習ではjupyter notebookを使用します。 インストールされているか確認してください。 インストールされていない場合、jupyterjupyter notebookのインストール方法については、レッスン33を参照してください。

演習前の基礎学習

実際にjupyter notebookを使用して演習を行う前に、演習の中で使用するPythonの機能について学習しましょう。

  • 書式化

    Pythonでprint関数の書式を指定するには書式化演算子(%)formatメソッドf文字列の3種類の方法があります。 f文字列についてはレッスン125ですでに説明しているので、今回は書式化演算子(%)formatメソッドについて説明します。

    • 書式化演算子(%)

      書式化演算子で書式を指定して新しい文字列を作成するには次のような形式になります。

      変換指定子を含む文字列 % 値
      変換指定子を含む文字列 % (値1, 値2, ...)
      

      まず、変換指定子を含む文字列についてです。 例えば、次のような文字列を例に考えてみます。

      "名前はxxです。年齢はyy歳です。"
      

      この文字列の名前の部分(xx)と年齢の部分(yy)に書式化を行った値を挿入して新しい文字列を作成したい場合、 以下のように、このxxとyyの部分にどのように値を書式化するかを表す%で始まる変換指定子を指定します。

      "名前は%-8sです。年齢は%03d歳です。"
      

      次に、書式化を行う値を指定します。 今回変換指定子を文字列の中に2つ記述しましたので、変換する値も2つ記述する必要があります。 値は文字列のあとに%を記述したあと、(値1, 値2)のようにタプルオブジェクト(書き換えのできない配列)として指定します。 タプルには変換指定子が記述された順番通りに要素として値を追加します。

      "名前は%-8sです。年齢は%03d歳です。" % ("Suzuki", 18)
      

      なお、変換指定子が1つの場合、値は1つとなり、この場合はタプルではなく値を直接記述することができます。

      "名前は%-8sです。" % "Suzuki"
      
      • 変換指定子の指定方法

        変換指定子は次のように記載します。

        % (マップキー) 変換フラグ 最小フィールド幅 精度 変換型
        

        変換指定子は%から始まり、(1)マップキー、(2)変換フラグ、(3)最小フィールド幅、(4)精度、(5)変換型、をそれぞれ指定します。 この中で必須な項目は(6)変換型だけで、(1)から(4)はオプションです。

        • 変換型

          必須項目である変換型は次の値が用意されています。

          "d" 符号付き10進整数
          "i" 符号付き10進整数
          "o" 符号付き8進数
          "x" 符号付き16進数(小文字)
          "X" 符号付き16進数(大文字)
          "e" 指数表記の浮動小数点数(小文字)
          "E" 指数表記の浮動小数点数(大文字)
          "f" 10進浮動小数点数
          "F" 10進浮動小数点数
          "g" 浮動小数点数。指数部が-4以上または精度以下の場合は小文字指数表示、それ以外の場合は10進表記。
          "G" 浮動小数点数。指数部が-4以上または精度以下の場合は大文字指数表示、それ以外の場合は10進表記。
          "c" 文字一文字(整数または一文字からなる文字列)
          "r" 文字列(Pythonオブジェクトをrepr()で変換)
          "s" 文字列(Pythonオブジェクトをstr()で変換)
          "a" 文字列(Pythonオブジェクトをascii()で変換)
          "%" 引数を変換せず、返される文字列中では文字'%'になります
          
        • マップキー

          値を指定する時にタプルではなく辞書を使用する場合に使います。 マップキーは()で囲って指定します。

          以下の例では、2つの変換指定子にそれぞれ(decnum)(hexnum)というマップキーを指定しています。 そして値を指定する時に、タプルではなく辞書を使い、辞書の要素毎にキーには変換指定子に指定したマップキーを指定し、値には変換指定子に渡す値を指定します。

          print("10進数=%(decnum)d, 16進数=%(hexnum)x" % {"hexnum":20, "decnum":20})
          >> 10進数=20, 16進数=14
          

          辞書の要素はどのような順番で記述されても構いません。

        • 変換フラグ

          変換フラグには次の値が用意されています。

          "#" 値の変換に"別の形式"を使う
          "0" 数値型に対してゼロパディング(0で埋める)を行う
          "-" 変換された値を左寄せする
          " " 符号付きの変換で正の値の場合、前に一つスペースをあける(-とそろえるため)
          "+" 変換の先頭に符号文字('+'または'-')を付ける
          

          変換フラグに"#“を指定した場合、変換型に"o"を指定すると8進数を表す接頭辞(0o)が、 “x"を指定すると16進数を表す接頭辞(0x)が、“X"を指定すると16進数を表す接頭辞(0X)が、 それぞれ最初の数字の前に挿入されます。

          print("数値1=%x, 数値2=%#x" % (30, 30)")
          >> 数値1=1e, 数値2=0x1e
          

          変換フラグに"0"を指定した場合、この後説明する最小フィールドよりも数値の桁数が小さかった場合に0で埋められます。 この変換フラグを指定していない場合はスペースで埋められます。

          print("数値1=%5d, 数値2=%05d" % (30, 30)")
          >> 数値1=   30, 数値2=00030
          

          変換フラグに”-“を指定した場合、この後説明する最小フィールドよりも数値の桁数が小さかった場合に左寄せで表示します。 この変換フラグを指定していない場合は右寄せで表示します。 下記の例では左寄せなのがわかりやすいように数値の前後に[]を付けています。

          print("数値1=[%5d], 数値2=[%-5d]" % (30, 30)")
          >> 数値1=[   30], 数値2=[30   ]
          

          変換フラグに” “を指定した場合、正の値の場合だけ数値の前にスペースを1文字入れ、負の値と桁数がそろうようにします。

          print("数値1=%d, 数値2=%d, 数値3=% d, 数値4=% d" % (30, -30, 30, -30)")
          >> 数値1=30, 数値2=-30, 数値3= 30, 数値4=-30
          

          変換フラグに”+“を指定した場合、数値の先頭に”+“または”-“を付けます

          print("数値1=%+5d, 数値2=%+5d" % (30, -30)")
          >> 数値1=+30, 数値2=-30
          
        • 最小フィールド幅

          最小フィールド幅は、少なくとも確保される桁数を指定します。 例えば数値や文字列が3桁で、最小フィールド幅が5だった場合には、5桁の場所に3桁の数値や文字列を表示します。 変換フラグを指定しないと、右寄せで表示され、空いてる部分にスペースが表示されますが、 変換フラグを指定することで、左寄せにしたり、0で埋めたりすることができます。 また、最小フィールドより値が大きい桁数だった場合は、最小フィールドの値は無視され、そのまま表示されます。

          print("数値1=%d, 数値2=%4d, 数値3=%4d" % (30, 30, 72536))
          >> 数値1=30, 数値2=  30, 数値3=72536
          

          なお、最小フィールド幅に”*“を指定した場合、最小フィールド幅を値の方で指定することができます。 この場合、最初に最小フィールド値を指定してから実際の値を指定します。

          print("数値1=%d, 数値2=%*d" % (18, 5, 42)")
          >> 数値1=18, 数値2=   42
          

          変換指定子は2つですが、値の方は3つ指定しています。 最初の値(18)は、最初の変換指定子(%d)で変換する値。 2つ目の値(5)は2つ目の変換指定子(%*d)の最小フィールド幅。 3つ目の値(42)は 2つ目の変換指定子(%*d)で変換する値です。 最小フィールドの方から先に値を指定する点に注意してください。

        • 精度

          最後は精度です。 小数部分の精度(桁数)を指定します。 何も指定しないと6桁になります。 指定する場合にはドット(.)のあとに桁数を指定してください。

          print("数値1=%f, 数値2=%.3f" % (1/3, 1/3))
          >> 数値1=0.333333, 数値2=0.333
          

          なお、精度に”*“を定した場合、精度を値の方で指定することができます。 この場合、最初に精度を指定してから実際の値を指定します。

          print("数値1=%f, 数値2=%.*f" % (1/3, 3, 1/3))
          >> 数値1=0.333333, 数値2=0.333
          

          変換指定子は2つですが、値の方は3つ指定しています。 最初の値(1/3)は、最初の変換指定子(%f)で変換する値。 2つ目の値(3)は2つ目の変換指定子(%*f)の精度。 3つ目の値(1/3)は2つ目の変換指定子(%*f)で変換する値です。 精度の方から先に値を指定する点に注意してください。

    • formatメソッド

      formatメソッドで書式を指定して新しい文字列を作成するには次のような形式になります。

      変換指定子{}を含む文字列.format(値1, 値2, ...)
      

      まず、変換指定子{}を含む文字列についてです。 例えば、次のような文字列を例に考えてみます。

      "名前はxxです。年齢はyy歳です。"
      

      この文字列の名前の部分(xx)と年齢の部分(yy)に書式化を行った値を挿入して新しい文字列を作成したい場合、 以下のように、このxxとyyの部分にどのように値を書式化するかを表す{}で変換指定子を指定します。

      "名前は{0:<8s}です。年齢は{1:03d}歳です。"
      

      次に、書式化を行う値を指定します。 今回変換指定子を文字列の中に2つ記述しましたので、変換する値も2つ記述する必要があります。 値は文字列のあとに.format()メソッドを指定し、(値1, 値2)のようにメソッドの引数として指定します。 引数には変換指定子で指定した0から始まるインデックスの順にしたがって値を指定します。

      "名前は{0:>8s}です。年齢は{1:03d}歳です。".format("Suzuki", 18)
      

      なお、変換指定子と引数が左から順に1対1になっている場合は、以下のようにインデックス番号を省略できます。

      "名前は{:>8s}です。年齢は{:03d}歳です。".format("Suzuki", 18)
      
      • 変換指定子の指定方法

        変換指定子は次のように記載します。

        {インデックス番号:文字寄せ 最小幅 カンマ 精度 型}
        
        • 型(タイプ)の指定

          一般に用いられる型

          記号型(タイプ)備考
          c文字列省略時は文字列なので、通常は省略する
          d整数(10進数)2進数はb、16進数はx(小文字)またはX(大文字)
          eまたはE浮動小数点(指数表記)大文字(E)の場合は指数表記がeではなくE
          fまたはF浮動小数点(小数点表記)大文字(F)の場合はnanがNAN、infがINF
        • 精度(小数点以下の桁数)

          「小数点以下?桁」を指定するには、{:.?f}のようにピリオド.の後に整数で桁数を指定します。

          print("{:.1f}, {:.2f}, {:.5f}".format(0.01, 0.01, 0.01))
          >> 0.0, 0.01, 0.01000
          

          指数表記の場合は以下のようにeまたはEを用います。

          print("{:.1e}, {:.2e}, {:.5e}, {:.5E}".format(0.01, 0.01, 0.01, 0.01))
          >> 1.0e-02, 1.00e-02, 1.00000e-02 1.00000E-02
          

          また、この精度指定を文字列型に使用すると、文字列を最大何文字使用するかを指定できます。

          print("{:.2}, {:.3}, {:.7}".format("abcde", "abcde", "abcde"))
          >> ab, abc, abcde
          

          なお、当然ですが精度は整数型(d, b, o, x, X)には使用できません

        • カンマ(千の位ごと)

          千の位ごとに「カンマ(,)」を入れたい場合は、以下のように,を指定します。

          print("{0:,}".format(1234567))
          >> 1,234,567
          

          小数点以下の精度指定と併記する場合は、以下のように,は左に入力します。

          print("{0:,.2f}".format(1234567))
          >> 1,234,567.00
          
        • 最小幅

          最小幅は、桁数指定の前で指定します。 最小幅とは「これ以上狭くならない幅」のことであり、列の幅を揃えたい場合などにるよう出来ます。 最小幅に足りない場合、後で説明するパディングを指定しなければスペースで埋められます。

          以下の浮動小数点型の例で、{:3.5f}では幅に3を指定していますが、データの0.01.5fで小数点以下5桁まで表示されるので0.01000と幅は7になります。

          このようにデータの表示が最小幅に足りている(最小幅以上)の場合は、データの部分は削られることなくそのまま表示されます。 一方、{:10.5f}で最小幅を10に指定して0.01を表示するとデータ幅は73足りないので、左側を3つのスペースで埋めます。

          print("'{:3.5f}', '{:10.5f}'".format(0.01, 0.01))
          >> '0.01000', '   0.01000'
          

          文字列型の場合も同様に指定した最小幅に足りない場合は、スペースで埋められます。 ただし、文字列型では右側を空白で埋めます。

          print("'{:2}', '{:10}'".format("abcde", "abcde"))
          >> 'abcde', 'abcde     '
          

          整数型の場合は、浮動小数点型と同様に、最小幅に足りない場合は左側をスペースで埋めます。

          print("'{:2d}', '{:10d}'".format(100, 100))
          >> '100', '       100'
          
        • 文字寄せ(パディング)

          何も指定しないと数値は右寄せ、文字は左寄せです。 文字列を右詰めしたい場合は、頭に>を付けます。

          print("'{:>20}'".format("abcde"))
          >> '               abcde'
          

          スペースの部分を任意の文字で埋めたい場合は、>の前に文字(1文字)を指定します。

          print("'{:*>20}'".format("abcde"))
          >> '***************abcde'
          

          数値の空白部分をゼロ(0)で埋めたい(ゼロパディング)場合には、最小幅の頭に0を付けるだけでできます。

          print("{:02d}, {:010d}".format(100, 100))
          >> 100, 0000000100
          
        • インデックス番号

          どの引数を表示するかは0から始まるインデックス番号で指定します。 インデックス番号は昇順に指定する必要はありません。 また同じインデックス番号を繰り返し使用しても構いません。

          print("xyz={1}, abc={0}, abcxyz={0}{1}".format("abc", "xyz"))
          >> xyz=xyz, abc=abc, abcxyz=abcxyz
          
          • インデックス番号の代わりにキーワードを指定する

            インデックス番号の代わりに キーワードを指定することもできます。

            以下のように文字列の中に{キーワード}を埋め込み、format()メソッドの引数に、キーワード=値を入力すると{キーワード}の部分を指定した値に置換してくれます。

            print("私の名前は{name}、年齢は{age:d}歳です。".format(name="小野寺健", age=66))
            >> 私の名前は小野寺健年齢は66歳です
            
          • リストやタプルを埋め込む

            引数にリスト、タプル、辞書などを設定し、{}の中のインデックスに[添字]を付けることで、リストやタプルなどの要素を埋め込むことができます。

            "{0[添字]}, {0[添字]}, {1[添字]}, {1[添字]}".format(リスト1, タプル1)
            

            リストを例に取ると、以下のような使い方ができます。

            apple, orange = 50, 100
            total = apple + orange
            price = [apple, orange, total]
            
            print("りんご:{0[0]}円 みかん{0[1]}円 合計:{0[2]}円".format(price))
            >> りんご50円 みかん100円 合計150

            先ほどのキーワードと組み合わせることも可能です。

            apple, orange = 50, 100
            total = apple + orange
            price = [apple, orange, total]
            
            print("りんご:{price[0]}円 みかん{price[1]}円 合計:{price[2]}円".format(price=price))
            >> りんご50円 みかん100円 合計150
    • isprintableメソッド

      print関数を実行した際に文字列がすべて出力できる場合はTrue、出力できない文字が含まれている場合はFalseを返します。

      "I am studying python".isprintable() # True
      "I am\n studying\a python" # False
      
  • リスト(配列)

    複数の要素を配列としてまとめたものをPythonでは**リスト(list)**と呼びます。

    • リスト表示演算子([])

      以下のように、[]の中に要素を,で区切って入れることでリストを作成することができます。 リストをprint関数で表示すると[要素1, 要素2, ...]のように表示されます。

      fruits = ["apple", "banana", "melon"]
      print(fruits)
      >> ['apple', 'banana', 'melon']
      

      作成したリストの各要素は0から始まるインデックス番号を使いリスト[インデックス番号]で取り出したり書き換えたりすることができます。

      fruits = ["apple", "banana", "melon"]
      print(fruits[0], fruits[1], fruits[2])
      >> apple banana melon
      fruits[0] = "orange"
      print(fruits)
      >> ['orange', 'banana', 'melon']
      

      なお、配列の要素数以上のインデックス番号を指定するとエラーになります。

      num = []のように空のリストを作成することもできます。 空のリストには後からappendメソッドなどを使用して要素を追加することができます。

      リストの要素には、数値、文字列を始めとして様々な型の値を入れることができます。 CやJavaなどの言語の配列とは異なり、Pythonのリストでは要素の型は要素ごとに異なっていても構いません。 ただし、要素の型が要素ごとに異なっている場合、要素に応じて処理を変えなければならないので注意が必要です。 したがって、要素の型は同一にする方が一般的です。

      リストの要素にリストを入れることができます。 これによって多次元配列を実現することができます。

      nums = [[0, 1, 2], [3, 4, 5], [6, 7, 8]]	# 3x3の2次元配列
      
    • list関数

      list関数を使ってリストを作ることもできます。

      num = list()のようにすると空のリストが作成されます。

      list関数の引数に、リスト、タプル、文字列、rangeなどiterable(イテラブル、反復可能オブジェクト)を渡すとその反復内容から新たなリストを作成します。

      
      num = list((1, 2, 3, 4, 5))
      print(num)
      >> [1, 2, 3, 4, 5]
      chars = list("ABCDEF")
      print(chars)
      >> ['A', 'B', 'C', 'D', 'E', 'F']
      
    • range関数

      for文でよく使われるrange関数は、規則的に連続する数値のiterableを出力する関数です。

      range(初期値、終端値、加算値)で、引数が1個のときは終端値のみ(初期値は0、加算値は1)、引数が2個のときは初期値と終端値(加算値は1)となります。

      前述のlist関数の引数として使用することで、規則的に連続する数値のリストを作成することができます。

      nums = list(range(10))
      print(nums)
      >> [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
      nums = list(range(1, 10, 2))
      print(nums)
      >> [1, 3, 5, 7, 9]
      
    • *演算子

      リストに*演算子を適用するとリストの内容を指定した回数繰り返したリストを返します。

      nums = [1, 2, 3] * 3
      print(nums)
      >> [1, 2, 3, 1, 2, 3, 1, 2, 3]
      nones = [None] * 3
      print(nones)
      >> [None, None, None]
      

      *演算子はコピーして繰り返されるので、要素がリストなどの場合、同じリストが繰り返され、どれかのリストを変更するとコピーされた全てのリストの内容まで変更されてしまうので注意が必要です。

      nums = [[1, 2, 3]] * 3
      print(nums)
      >> [[1, 2, 3], [1, 2, 3], [1, 2, 3]]
      nums[0][0] = 4
      print(nums)
      >> [[4, 2, 3], [4, 2, 3], [4, 2, 3]]
      

      したがって、多次元配列を作成する時に*演算子を使うことはできません。 多次元配列を作成する際には、次のレッスンで学ぶ内包表記を使用します。

    • appendメソッド

      リストに要素を追加するにはappendメソッドを使用します。 リスト.append(要素)で要素をリストの最後尾に追加します。

      nums = []
      nums.append(1)
      nums.append(2)
      nums.append(3)
      print(nums)
      >> [1, 2, 3]
      
    • len関数

      len(リスト)のようにリストを引数としてlen関数を実行するとリストの長さを返します。

      nums = [1, 2, 3, 4, 5]
      print(len(nums))
      >> 5
      
    • countメソッド

      リストに引数の要素が何個含まれているかを返すのがcountメソッドで、リスト.count(要素)のように使用します。

      nums = [1, 1, 2, 3, 3]
      print(nums.count(1))
      >> 2
      print(nums.count(2))
      >> 1
      print(nums.count(3))
      >> 2
      print(nums.count(0))
      >> 0
      

演習

それでは実際にjupyter notebookを使用して、演習を行います。

コマンドラインからgit pullを実行してmcc1フォルダに最新のファイルをダウンロードしてください。

ターミナルのコマンドラインからcd mcc1/code/jupyterを実行して、jupyterフォルダに移動し、jupyter notebookを実行してください。

すると、ブラウザが起動し、jupyterのホーム画面が表示されます。

その中からPython演習ドリル200基礎練習51〜60.ipynbをクリックしてください。

そうするとPython演習ドリル200基礎練習51〜60というタイトルの演習問題が表示されます。

課題51から課題60までありますので、課題の内容にしたがって、In[]:の部分にPythonプログラムを書いてください。 書き終わったら、画面上の ▶| Run というアイコンをクリックすると、今書いたPythonプログラムが実行されます。

出力結果が課題の(実行画面)と一致するか確認してください。

どうしても正解がわからないときは、▶プログラム例 をクリックすると、正解例のPythonプログラムが表示されます。

まとめ

今回はPython演習として、書式化のつづき(書式化演算子とformatメソッド)とリストを行いました。

今後も新しい演習問題を追加していきますので、演習を通じてPythonを学んでいきましょう。