関数とモジュール

    • 菊地先生のオンラインテキスト 2006年度版に基づく
    • 前回同様、演習ディレクトリ(今回はpython/05)を作成してから実施。

    関数

    • これまで,いろいろな形で既存の関数を使ってきました。
      • 例: input(), math.sin() など
    • 関数を自分で作成することもできます。今回は自分で関数を作る方法を見ていきます。
    • 教科書では4章を復習しておいてください

    関数を作ってみる

    • インタラクティブモード(コマンドpythonで起動)で下記のように入力してみてください。
    • >>> def tax(x):
      ... a = 1.08
      ... print('税込み', x * a, '円')
      ...
      >>>
    • この例では,関数 tax(x) を def ... に続く2行で定義しています。
    • この2行は,関数の中であることを示すために,頭下げ(インデ ント,半角4スペース)していることに注意してください。
    • 最後には何も入れずリターンしてブロックから抜ける

    できた関数を使ってみる

    • この関数を使うには,次のように入力します。
    • >>> tax(360)
      税込み 388.5 円

    値を返す関数

    • math.sin() のように値を返す関数を作りたい場合には,return を使って値を返します。
    • >>> import math
      >>> def func(x):
      ... y = math.sin(x)/x
      ... return y
      ...
      >>> func(0.1)
      0.99833416646828155

    関数をモジュールに作る

    • 以上はインタラクティブモードでの実行でしたが,作成した関数を再利用できるようにするには,"モジュール"を作成します。
    • モジュールはファイルに作成します。
    • 下記の内容をファイルtablef.pyとして作成して ください
      • これはコピーペーストとするとエラーになる。下の白い表をコピーしてください)。
    • # tablef.py ... 表に関するモジュール
      def multable(n):
      table = []        # 空のリスト tableを作成
      for i in range(1, n+1):
      row = []       # 空のリスト rawを作成しなおす
      for j in range(1, n+1):
      row.append(i*j)  # raw に i*jの値を付け加える(appendについてはコラム参照)
      table.append(row)   # table に rawを加える(2次元のリストになる)
      return table
    • コピーする場合はこちらを
    #tablef.py   表に関するモジュール
    def multable(n):
        table = []                              
        for i in range(1,n+1):   
            row= []                              
            for j in range(1,n+1):
                row.append(i*j)              
            table.append(row)
        return table

    モジュールの利用

    • 自分で作ったモジュールを Python インタラクティブモードで使ってみましょう。
    • 注:カレントディレクトリにa.pyがないとエラーになります。 a.py のあるディレクトリで コマンドpythonを入力してください。
    • >>> import tablef
      >>> tablef.multable(3)
      [[1, 2, 3], [2, 4, 6], [3, 6, 9]]

    スクリプトから呼び出す

    • 次に,tablef モジュールを使って掛け算表を整形して印刷するような Python スクリプト (b.py) を作ってみましょうこれもコピーペーストするとエラーになるので下の白い表をコピーしてください。
    • 注意:このときa.pyとb.pyは同じディレクトリにある必要があり ます。
    • #!/usr/bin/env python3
      # -*- coding: utf-8 -*-
      import sys
      import tablef #モジュールtablef.pyを読み込む
       
      # コマンドラインから n を取り出す
      n = int(sys.argv[1]) #一つ目の引数を整数に変換し,nに代入

      # 掛ける数を最初に印刷
      for i in range(1, n+1):
      print ('%3d' % i, end='')
      print()
      print('----' * n)

      # モジュールから表作成関数を呼び出す
      t = tablef.multable(n) #モジュールaの関数multableを呼び出し,返り値(table)をtに代入

      # 結果を整形して印刷
      for x in t: #table t 内の list(行) を順番に xとして 繰り返し処理
      for y in x:       #list x 内の 要素 を 順番に yとして 繰り返し処理
       print ('%3d' % y, end='')
      print()
    コピーするときはこちら (b.py)
    #!/usr/bin/env python3
    # -*- coding: utf-8 -*-
    # b.py
    import sys
    import tablef

    # コマンドラインから n を取り出す
    n = int(sys.argv[1])

    # 掛ける数を最初に印刷
    for i in range(1, n+1):
        print ('%3d' % i, end = '')
    print()
    print ( '----' * n)

    # モジュールから表作成関数を呼び出す
    t = tablef.multable(n)

    # 結果を整形して印刷
    for x in t:
        for y in x:
             print ('%3d' % y, end = '')
        print()


    実行例は以下のようになる

    • $ ./b.py 3
      1 2 3
      ------------
      1 2 3
      2 4 6
      3 6 9

    コラム

    上記のtablef.py, multableのなかの appendは、リストという変数型に対してあらかじめ準備されている手続 きで、"メソッド"といいます。(厳密にいうと、メソッドとは、あるデータ型が専用に持っている関数です。)

    リストのメ ソッドには下記のようなものがあります  

    append(x) リストの最後に x を付け加える。
    count(x) リスト中に x が出現する回数を返す。
    index(x) リスト中で x が最初に現れる位置を返す。
    insert(i,x) リストの i 番めに x を挿入する
    remove(x) リストにある最初の x を削除する。
    del(i)
    i 番めの要素を削除する。
    reverse()
    リストを逆順にする。
    sort() リストを整列する

    実際にこれらのメソッドを使うには,たとえば aというリストに対して利用するには a.メソッド名(引数)として利用する。
    >>> a=[4,5,6,2,1]
    >>> a.sort();
    >>> a
    [1, 2, 4, 5, 6]

    関数作成のコツ
    • 汎用性(様々な用途や場面で使用出来ること)を意識する
    • 引数の数はなるべく少なくする
    • 戻り値はシンプルに考える

    • つまり、使用する人が中身をみなくても誤解せずに安心して使えるように設計する事が望ましい

    まとめ

    関数の定義法

       def 関数名(引数1,引数2, ...)
           関数内の実行文1(先頭は、半角4文字インデント)
           関数内の実行文2(先頭は 半角4文字インデント)
         .....
    値を返す関数の場合は,実行文の中(通常,最後)に "return 変数名" を加える
      
    モジュールの利用

    (1)関数をファイル(〜.py)に保存する

    (2)関数を呼び出す

    • インタラクティブモードで利用する場合
      • import ファイル名 (..pyを除く)
      • ファイル名(.pyを除く).関数名(引数1,引数2, ...)として呼び出す

    • スクリプトで利用するとき
    #!/usr/bin/env python3
    # -*- coding: utf-8 -*- ここより後で,ファイルをインポート  
    import モジュール(ファイル)名  (.pyを除く)
    ......
    モジュール(ファイル)名(.pyを除く).関数名(引数1,引数2, ...)として呼び出す   

    課題

    以下の問題の解答(スクリプト,モジュールと実行例) をメールで送ってください。作業はpython/05のなかで行うものとし,作成したスクリプトは残しておいてください 。(評価の対象とします)。今回はスクリプトは添付ではなく、メールの中にコピーしてください

    メールあて先:           honda@is.kochi-u.ac.jp
    サブジェクト名:        p5 kadai
    締め切り       :         12/21 17:00

    1.半径rの円の面積を戻す関数 carea(r)を モジュールq1.pyに作成しなさい。また,インタラクティブモードで正しく動作することを確認しなさい。解答には,q1.pyの中身と実行結果を含めてください。

    実行例
    python                 (インタラクティブモード)
    >>> imort q1
    >>> q1.carea(3)
    28.274333882308138
    .......

    2.r! (1x2x.......r) を計算してその値を戻す関数kaijo(r)をモジュール q2.pyに作成して、インタラクティブモードで正しく動作することを確認しなさい。解答には,q2.pyの中身と実行結果を含めてくださ い。

    実行例 (python interactive mode)
    >>> imort q2
    >>> q2.kaijo(4)
    >>>24    

    3.  2で作成したkaijo(r)を利用して,nCr(注1)を計算する"スクリプ ト"cmb.pyを作成しなさい。nとrは下記のように、スクリプトの引数で指定するようにしてください。
    また, r>nが入力された場合には下記のようなエラーメッセージが出るようにしてください。

    入力値が不正です.
    用法: cmp.py n r(nCr、n>=r)

    解答には,cmb.pyの中身と実行結果 を含めてください。
    実行例
    % chmod +x cmp.py
    % ./cmp.py 6 2

    6C2=15
    % ./cmp.py  4  5
    入力値が不正です.
    用法:  cmp.py  n   r(nCr、n>=r)


    ヒント:nCr=n!/(r!・(n-r)!)

    ーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーーー

    参考問題

    提出の必要はありませんが,余力のある人は解いてみてください。
    1. 2次方程式 a x2 + b x + c = 0 の解を公式によって計算する関数 solve(a, b, c) を モジュール(q1.py)に作成しなさい。以下の実行例を参考にしなさい。
      注)平方根の計算 ... math.sqrt() / 利用可能な関数については Python のオンラインマニュアルも参考にしてください。

          >>> from q1 import solve
          >>> solve(1.0, 0.0, -1.0)
          解は:  1.0 , -1.0
          >>> solve(1.0, -2.0, 1.0)
          解は:  1.0
          >>> solve(1.0, 0.0, 1.0)
          実数の範囲を越えます