eljefeblog 

Any sufficiently advanced technology is indistinguishable from magic

programming python-basic-lectures

【基本を学ぶ6:超初学者向け】Pythonプログラミング入門【関数応用編】

Pythonプログラミング入門【関数応用編】



本シリーズでは、後づけでも構わない情報を削ぎ落とし
頭に入れておく事でPythonプログラミングの概要を捉える事ができる
コアな情報を厳選しています。

(初めからしっかり学びたい方はこちら↓↓)



このシリーズを最後まで学習することで
Pythonプログラマとして太い知識の主軸を積み上げる事ができます。


悩むペン銀

関数定義についてさらに深く学びたい

実践的に関数を使う場合、どのような事ができるのだろう?


本記事ではこのような疑問に答えていきます。



本記事の内容

  • yieldを使った関数の応用方法
  • lambdaを使った簡略的な関数定義の方法
  • importを使ったモジュールの利用方法





  • 少し応用編:関数を深く知る


    yieldを知る



    前回関数において最後にreturnを宣言する事で
    実行を終了し、値を返す事ができました。

    def 関数名(引数1, 引数2, 引数3, …):
           ….
           return



    しかし、Pythonにはもう一つyieldというキーワードが用意されており、
    この宣言を行う事で、関数の実行を一時的に止めて、値を返す事ができます。


    定義の方法はreturnのそれとほとんど同じです。
    関数ブロック内での計算結果の値を返します。

    def 関数名(引数1, 引数2, 引数3, …):
           ….
           yield


    yieldを詳しく理解するためには
    イテレータジェネレータに関する知識が必要です。

    少し学んでみましょう。



    イテレータとジェネレータ



    各説明は以下のようになります。

  • イテレータとは、「繰り返し要素を取り出す事が可能なデータ型」の事です。
    Pythonではリスト型や辞書型, タプル型, セット型などがこれに当てはまります

  • 一方ジェネレータはイテレータの一種であり
    その名の通り「要素を生成できる機能を持ったオブジェクト」を指します。
    そしてこのジェネレータを作るのにyieldを利用できます。


  • 普通の関数と何が違うのか確認していきましょう。
    以下にreturnを利用した関数my_function_return()を用意します。

    >>> def my_function_return():
    ...     x = 4
    ...     y = 11
    ...     sum_ = x+y  
    ...     return sum_
    ... 
    >>> my_function_return()
    15


    関数内でxとyの値を足し算し、その結果をreturnで返している事がわかります。
    関数が実行されると、returnでその実行が終了します。


    一方でyieldを利用した関数をみてみましょう。

    >>> def my_function_yield():
    ...     x = 4
    ...     y = 11
    ...     sum_ = x+y
    ...     yield sum_
    ...     
    ...     x = 33
    ...     y = 14
    ...     sum_ = x+y
    ...     yield sum_
    ...
    >>>
    >>> my_function_yield()
    <generator object y at 0x10e75d6e0>
    >>>
    >>>
    >>> for i in my_function_yield():
    ...    print(i)
    ...
    15
    47


    yieldが含まれる関数は「ジェネレータのオブジェクト」として扱われます。
    for文で値を確認してみると各yield ごとに
    xとyの和である値がそれぞれ返されていることが分かります。

    このようにyieldを使うことで
    「関数における途中の値を取得するできる」ようになります。



    組み込み関数next()を利用する


    さらに、組み込み関数next()を使うことで
    同様の処理を実現することができます。

    >>> generator = my_function_yield()
    >>> next(generator)
    15
    >>>
    >>> next(generator)
    47
    >>> 
    >>> next(generator)
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    StopIteration



    このように複数回next()関数を実行する事で
    yieldが宣言された回数分、対象の値を返すことができます。


    この具体例ではyieldする値が2回であるのに対し
    3回関数my_function_yield()を呼び出したため
    これ以上出力する値が無いことを伝える
    StopIterationが出力されました。


    yieldを使う理由



    yieldを使用する利点としては
    例えばメモリに負担がかかるため分割して値を生成する事が考えられるでしょう。大量のデータを処理する場合など、プログラミングの経験値が上がっていくと必要性を感じ始めると思います。


    初学者の方はあまり頻繁に利用する事がないかもしれません。
    とりあえずその存在を頭の片隅に入れておきましょう。

    今はyieldがあるんだな〜という感じで覚え方でも大丈夫です。
    このシリーズの続編で何度も出てきます。



    lambdaで関数を作る



    前々回defというキーワードを利用して定義する事を学びました。
    定義した関数には関数名をつけ、関数名(引数)という形で値を呼び出しましたね。


    関数定義の意義はこれまで書いてきたコードを
    何度でも再利用可能にするための仕組みにあり
    名付けられた関数名と引数を1行のラインで表す事ができるため
    再び複数行のコードを書く事なく、簡単に計算結果を得る事ができました。


    しかしPyhtonではもっと短く、簡略的に関数定義を行う事ができます。
    この方法で関数を定義する場合、関数名はなくその計算結果のみを返します。
    ここで登場するのがlambda(ラムダ)です。



    lambdaは以下のように定義し利用します。

    lambda 引数: 返り値


    defとlambdaの違い


    具体的にこれまでの関数定義と何が異なるのか
    defを使った関数定義とlambdaを使った関数定義を
    それぞれ比べてみましょう。どちらも同様の計算をします。


    defを使った関数定義

    >>> def new_function(arg):
    ...     return arg*2
    ...
    >>> new_function(2)
    4



    lambdaを使った関数定義

    >>> new_function = lambda  arg: arg * 2
    >>> new_function(2)
    4



    defでの関数定義に比べlambdaでの関数定義の方が
    数行ですが、簡潔に書けている事が分かるはずです。


    変数new_functionが関数として機能するようになります。
    lambdaと関数との決定な違いは明示的に関数名を定義しないという事です。
    変数に関数オブジェクトを代入する事で関数を生成します。



    どの場面で役に立つのか


    ここで、ではlambdaどんな時に役に立つの?
    という疑問が湧いてきたかもしれません。

    この答えはズバリ
    わざわざ関数を定義する必要がない時
    (定義しても何度も呼び出す事が想定されない時)です。
    関数は貴方がある目的のため一生懸命書いた長いコードを
    「繰り返し再利用できること」に存在意義があります。


    Pythonには何度も利用しない関数はできるだけその数を減らして
    プログラムを綺麗な状態にしたいという思想
    があるのです。


    役に立つ実例をあげるのであれば
    例えば、a = [1, 2, 3, 4, 5, 6]というリスト型のデータがあり
    それぞれ各要素に3掛け9を足す計算をしたい時が想定されます。


    これは組み込み関数であるmap()lambdaを同時に利用する事で
    簡単に実現する事ができます。


    組み込み関数map()



    組み込み関数map()

    map(関数, 繰り返し可能なデータ)



    という引数をとります。
    ここでの繰り返し可能なデータとはリストや辞書といった
    複数のデータを保有しているオブジェクトのことです。


    この関数を用いることで、1つ1つの要素に対する処理を
    リスト等に格納された 全てのデータに対して行うことを実現できます。


    故に、mapとlambdaを同時に利用してみると
    以下のような動作を簡潔にコーディングする事ができるのです。

    >>> list_input = [1,2,3,4,5,6]
    >>> list_output = map(lambda list_input: list_input*3+9, list_input)
    >>> list_output
    [12, 15, 18, 21, 24, 27]



    1行目にlist_inputにリスト型のデータが格納されています。


    2行目ではmap(関数lambda, list_input)とデータが関数lambdaに渡され
    list_inputに格納された各要素に対して3を掛けて9を足すという計算を行い
    その結果をlist_outputに代入しているのが分かるでしょう。


    結果として得られた値は
    [12, 15, 18, 21, 24, 27]となりました。
    自分の手を動かしてこの結果になるか、確認してみましょう。


    この使い方は何度も使う場面が訪れるため
    習得しておくととても役に立ちますよ!



    Python標準ライブラリを利用する



    これまですでにPythonに用意された組み込み関数や自作の関数定義について学んできました。しかし組み込み関数だけではなく、Pythonのメンテナンスを行うエンジニアがPythonを使う人々のために、プログラムの開発速度向上を目的に、質の高いモジュールを用意してくれています。


    基本的にこういったモジュールは定期的にメンテナンスされており
    プログラムの信頼性は高いと言えるでしょう。
    エンジニアをしているとほぼ毎日使うことになります。

    *モジュールとは拡張子「ファイル名.py」で保存されたファイルを意味します。多くの関数が定義され、1つのファイルにまとめられたものです。



    また、これらモジュールを1つの冊子として集めたものをパッケージもしくは(ライブラリ)と呼びます。何かしらプロジェクトに携わると、これらを使わない手は考えられない事に気づくでしょう。


    モジュール自体は自分で定義することも可能です。
    これはファイルを編集する操作が必要となる為、この記事の続編で紹介します。


    まずは用意されたモジュールを利用してみましょう。
    以下のようにimportします。

    >>> import モジュール名



    今回はdatetime・math・randomの3つを紹介します。


    datetime

    datetimeでは「日付や時間といったデータ」を利用できるモジュールです。
    具体的には以下のような動作を実現します。

    >>> import datetime 
    >>> 
    >>> # 詳細な現在日時の取得
    >>> datetime.datetime.now()
    datetime.datetime(2019, 9, 26, 17, 27, 11, 251589)
    >>> # 左から(年,月,日,時,分,秒)
    >>>
    >>>
    >>> today = datetime.datetime.today()
    >>> today.year 
    2019
    >>> today.month
    9
    >>> today.day
    26
    >>> today.hour
    17


    math

    mathでは数学処理を行う関数を提供しています。
    具体的には以下のように利用します。

    >>> import math
    >>>
    >>>
    >>> math.exp(10) #eの(引数値)乗を計算し値を返す(e^10)
    22026.465794806718
    >>> 
    >>> math.log(5) # 引数の自然対数を計算し返す(log(5))
    1.6094379124341003
    >>>
    >>> math.sqrt(8) # ルート8の値を計算し返す
    2.8284271247461903



    random

    randomでは擬似乱数を生成し提供します。
    具体的には以下のように利用します。

    >>> import random
    >>> 
    >>> random.random() # 0以上1未満の乱数(浮動小数点数)を返す
    0.08528085602280977
    >>>
    >>> random.uniform(1,111) # 引数で指定した範囲内で乱数(浮動小数点数)を返す
    71.65925351405868
    >>>
    >>> random.randint(1, 10) # 引数で指定した範囲内で整数の乱数値を返す
    6



    さらに深く各モジュールについて知りたい方はこちらを確認してください。
    Pythonにはたくさんの種類ライブラリが用意されている事に気づくでしょう。
    今全てを覚える必要はありません。
    使っていくうちに、自然と身に付いていきますので大丈夫です。
    一つ一つやっていきましょう。



    まとめ



    いかがだったでしょうか?

    少し情報量が多くなってきたので
    今回はここまでにしましょう。


    本記事では関数についてより深く知り
    他者の書いたコードを利用する方法について学びました。
    Pythonの標準ライブラリには様々な種類のモジュールが用意されており
    利用する事でプロジェクトの開発速度を簡単に向上する事ができます。


    一度で全てを覚えようとすると、各モジュールにおいて凄まじい量のクラス
    、そして関数が用意されているためパンクしてしまいます。
    コピペを避け、何度もコードを書いていく事で身につける方が
    何倍も効率が良いでしょう。


    その点だけは手を抜かずに実践し続ける事をお勧めします。



    今回は以上です。
    ではでは





    人気記事【初学者必見】効率的なプログラミング勉強方法を紹介します

    人気記事 CS学位取得者がガチでプログラミングスクールを調査してみた件【おすすめのスクール】









    このエントリーをはてなブックマークに追加
    data-ad-format="rectangle" data-ad-format="rectangle"

    返信する

    メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

    某国立大学大学院(理系)に所属しています。 最近の趣味は人工知能関連の論文を読む事で 研究ではComputer Vision周りを中心に活動しており、 サイドワークとしてデータ分析の業務に関わっています。 本ブログはこれまで筆者が学んできた様々な知識の中から 有益だと思えた情報のみをまとめたものです。 内容は個人の見解であり、所属する機関と関係するものではありません。 Research: is related to Computer Vision Hobby: is to study Artificial Intelligence / Machine Learning.