eljefeblog 

Any sufficiently advanced technology is indistinguishable from magic

programming python-basic-lectures

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

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



本記事はPythonの基本を学ぶシリーズ続編です。
第一回はこちらの記事になりますので、初めからしっかり学びたい方は
順番に記事をご覧ください。↓


本シリーズでは、できるだけ不要な、後づけでも構わない情報を削ぎ落とし
頭に入れておかなくては、Pythonでのプログラミングに支障をきたす
コアな情報を厳選し学習を進めていける内容になっています。

悩むペン銀

Pythonに何ができるのか具体的に知りたい

Pythonの基本構文を学び、プログラミングの大筋を理解したい

Pythonを実際にコーディングして学習したい


具体的には上記の様な疑問に答えていきます。


さて、前回は
条件分岐およびループ処理を復習し
関数定義の基本について学びました。


本記事では関数定義に関する知識をさらに深め
オブジェクト指向の根幹であるクラス構文について学んでいきます。


今回は少し難しい内容になってきますが
一歩ずつ階段を登っていきましょう。






関数定義


いよいよPythonプログラミングの本質的内容に踏み込んでいきます。
本記事のメインである関数定義です。

これまでPythonにおける様々な構文を学んできました。
ある動作を実現する事を目的として
プログラムを書く事ができるようになってきたでしょう。

しかしこれまでの知識ではコードを一度書けば
一度変数の値を決めてしまえば, その値以外の動作は出来ない事に
薄々気付いている方もいるでしょう。

つまり再利用することは出来ず、使い捨て状態であったと言えます。
そこで関数の登場です。

関数とは1つのシンプルな動作を行う再利用可能なコードの事であり
これまで公式に用意された組み込み関数(len()..etc)やデータ型関数(.format()..etc)を学んで来ました。

しかし関数は自分でも定義する事が可能です。
Pythonでは関数を以下のような構文(決まりごと)に従い定義します。


関数のブロックは予約語defから始まり関数名、丸括弧最後にコロンで締める
また、どんなパラメータ(引数)もこの丸括弧内に設置しブロックの中で使用できる


実際には以下のように定義します。

>>> def my_function():
...     print("Hello World!")
>>>


Pythonではこのように関数を定義し
定義された関数を呼び出すには
以下のように実行します。

とても簡単ですね。
さらにこの関数にはパラメータを与える事ができます。
(この関数に与えられるパラメータnameはよく引数とも呼ばれます。)

>>> def my_function(name):
...     print("My name is: {}".format(name))     
...
>>> my_function("Seimei")
My name is Seimei
>>> my_function("Kyouka")
My name is Kyouka

引数nameは関数のブロック内において
同様の変数nameとして扱われます。


上記のコードでは引数として”Seimei”が与えられ
変数nameには”Seimei”が格納されます。
その変数が.format()関数に引き渡される事で
“My name is Seimei”の文字列が生成されるという流れです。


またここでの引数(パラメータ)の数は好きなだけ追加する事ができます。
以下のコードを確認してみましょう。(自分で入力して確かめる事が大切ですよ)

>>> def my_function_2(name_1, name_2) 
...     print("This is {} and this is {}".format(name_1, name_2))
...
>>> my_function_2("Seimei", "Yuuta")
This is Seimei and this is Yuuta
>>> my_function_2("Yukiko", "Ayari")
This is Yukiko and this is Ayari



この様に引数には制限がないためいくつも指定する事ができます。
また関数内では与えられた引数を利用し、数値計算も行う事が可能です。

>>> def my_function_3(number_1, number_2):
...     print(number_1 * number_2)
...
>>> my_function_3(4, 2)
8
>>> my_function_3(5, 10)
50

リストをパラメータとして渡すことも簡単です。

>>> def my_function_4(foods):
...     for food in foods:
...         print(food)
...
>>> meal = ["wine", "meat", "soup", "bread"]
>>> my_function_4(meal)
"wine"
"meat"
"soup"
"bread"



このように関数my_functionを定義し、パラメータを設定することで
様々な入力値を受け取り、その入力を加工して出力値を返す事ができます。

これでprint()関数やtype()関数といった組み込み関数同様に
自分が実現したい機能を持った
新しい関数を定義することができるようになりました。





ふりかえり


今回勉強したことの振り返りです。

関数とは自分で書いたコードを再利用できるものでした。
以下のような関数定義を行いましたね。
もう一度Pythonの対話環境でコードを入力し、確認してみましょう。

>>> def my_function(name):
...     print(name)
...
>>> my_name = my_function("seimei")
seimei
>>> my_name
>>>



前回、このように構文中にprint()関数を定義し
関数を呼び出した時, 値を出力させていましたが
関数にはreturnという予約語があります。


このreturnには値を返す機能があり
何かしらプログラムを書く際には
基本的にほぼ全ての関数にはreturnを持たせます。


実際に前回のprint()で終わる関数と
returnを使った関数の違いをみていきましょう。

>>> def my_function(name)
...     return name
...
>>> my_name = my_function("seimei")
>>> my_name
seimei



違いが確認できたでしょうか?
print()関数で終了している関数定義では引数nameに文字列を渡していても
“seimei”の文字列がprintされるだけで変数my_nameに値が代入されていません。


一方で, returnで終了している関数定義では変数my_nameに
引数の値を渡している事が分かります。


このように関数においてreturnを挿入する事で


  • ①値を引数として受け取り

  • ②関数内で操作を加え

  • ③出力として変数に渡す


  • といった一連の動作を実現できるのです。
    この機能を持っていることが関数としてとても重要な事であり
    後述するクラス定義において様々な機能を実現する根幹となります。



    関数を説明するDocString



    シリーズ第2回目の記事で、Pythonでは#(シャープ)の後に文章を書くことができる
    コメントアウトという概念があることを学びました。


    Pythonでは複数行にわたってコメントを記述することができるdocstringが用意されており、多くのプログラマはコーディングした関数がどのような動作をし、何の為に用意されたのか説明するためこれを利用します。


    具体的にはプログラムの実行時、#(シャープ)でのコメントアウト同様に
    docstringの文章は3つのクオーテーション”” “”内に文字を入力し、これが無視されるようになっています。


    例えば以下のように記述します。

    >>> goods_info_dic={"apple": 200, "water": 110, "bread": 400, "milk": 200}
    >>> def calculate_total_account(goods_info_dic):
    ...     """ 買い物の合計金額を計算し、その金額と個数を返す関数 
    ...         input: 商品とその値段(辞書型)
    ...         output: 商品の個数(整数型), 総額(整数型)
    ...     """
    ...     goods_counter = 0
    ...     total_price = 0
    ...     for good in goods_info_dic:
    ...         total_price += goods_info_dic[good]
    ...         goods_counter += 1 
    ...     return goods_counter, total_price    
    ...
    >>> total_num, total_price = calculate_total_account(goods_info_dic)
    >>> total_num
    4
    >>> total_price
    910



    ここで少しコードの説明をしましょう。
    9行目では受け取った辞書型のデータよりループ処理で
    キーである”apple”, “water”, “bread”, “milk”を goodという変数に代入しています。
    1回のループで前に代入された値が更新される仕組みです。


    10行目では1行目に宣言された商品とその価格情報を持つ辞書goods_info_dic
    よりgoodに関連づけられた要素、即ち商品価格の値を持ってきて
    変数total_priceに代入していきます。


    11行目ではgoodが辞書goods_info_dicより取り出される毎、即ちループ回数毎にその回数をカウントしてgoods_counterに記録します。


    最後にそれら2つの値をreturnで返すという関数です。
    関数で計算した複数の値を変数に代入することができる点
    returnの便利な機能の1つであると言えるでしょう。


    このように
    docstringには上気した説明を簡略的に記述することになります。
    最低限以下の情報を加えることで、プログラムを見返した時理解しやすくなるでしょう。


  • ①その関数はどのような関数なのか概要

  • ②入力として(引数として)何を受け取り

  • ③どのような値を出力として返すのか



  • 後々振り返ってコードを確認する人を気遣い
    その人が即座にその関数について理解できるように説明文を添えることで
    プロジェクトの開発効率が格段に上がることでしょう。


    もちろんあなた自身もその恩恵を感じるはずです。
    是非、積極的にdocstringを書き残す習慣をつけてください。



    クラス定義



    いよいよここまできました。クラスは
    オブジェクト指向の言語において最も重要な構文であると言えるでしょう。


    少し歴史的背景を話しておくと
    オブジェクト指向の歴史は深くはなく、その起源となるアイディアが生まれてからおよそ40年程になります。その考え方が受け入れられ、実践的に利用される様になってからおよそ20年程です。


    1970年代中期、SmallTalk(Xerox PARC開発) や CLU(MIT開発)でオブジェクト指向のアイディアがサポートされましたが、実践的にはC++やJavaが開発されるまで実用性がないものでした。


    話を元に戻しましょう。
    第一回目の記事で説明した通り
    Pythonはオブジェクト指向のプログラミング言語でしたね。
    クラスはPythonプログラミングの中でも本当にコアの部分です。


    車を作り出すにはウィンカーやブレーキ
    アクセルやクラクションなど様々な機能を組み合わせる必要があるように
    プログラミングで目的のオブジェクトを実現させるには
    これまで学んできた様々な関数を組み合わせる必要があります。


    クラスとは言うなれば車というオブジェクト(物体)の事です。
    様々な機能を定義した関数を掻き集め、繋ぎ合わせ
    1つのオブジェクト(物体)を作成します。


    構文はclassという予約語を利用し
    以下の様な記述で定義します。

    >>> class MyClass:
    ...     x = 5



    最もシンプルなクラス定義は上記の様になります。
    class クラス名:(コロン)の順番でクラスを定義し
    ブロック内にはx=5という変数定義を行なっているのが分かりますね。


    それでは作成したクラスオブジェクトを生成してみましょう。
    以下の様に生成します。

    >>> my_object = MyClass()
    >>> my_object
    <__main__.MyClass instance at 0x1099833b0>
    >>> type(my_object)
    <type 'instance'>
    >>> print(my_object.x) 
    5



    クラス名()で変数に代入する事でクラスオブジェクトを生成(インスタンスとも呼ばれます)します。 my_objectをtype()関数を利用し呼び出した時
    出力がインスタンス型になっていることを確認してください。


    またクラス内に定義された変数にインスタンス.変数名
    アクセスすることが可能です。
    整数型の5が出力されている事がわかると思います。


    これで最もシンプルなオブジェクトを作成する事ができました。
    クラスにはさらに重要な機能がたくさんあります。
    先ずは以下のコードを確認してください。


    自己紹介をする、人間のオブジェクトをコーディングしてみましょう。


    >>> class Person:
    ...     def __init__(self, name, age):
    ...         self.name = name 
    ...         self.age = age
    ...     def my_function(self):
    ...         print("Hello my name is "+ self.name)
    ...         print("My age is "+ str(self.age))
    ...
    >>> person = Person("Jake", 28)
    >>> person.my_function()
    "Hello my name is Jake"
    "My age is 28"



    新しい組み込み関数__init__とキーワードselfが出てきましたね。
    よりクラスに対する知識を深めるため、これらについて学んでいきましょう。


    __init__関数



    全てのクラスはこの__init__という組み込み関数を持っており
    __init__はインスタンス生成される際、毎回実行される関数です。


    この関数にはそのオブジェクトがインスタンス生成される際
    特徴として持っていて欲しい値を変数に指定しておく事ができます。
    もしくはインスタンスを生成した段階で
    何かしら操作を実行したい場合も含まれます。


    上記のコードでは引数として与えられたnameおよびageの値が
    そのまま変数nameおよびageに代入されていきます。


    ここでselfという予約語が出てきています。
    selfとはなんなのでしょうか?


    selfとは


    selfとはインスタンス自体を表すキーワードです。
    つまり上記のコードではPersonというクラスオブジェクト自体
    を指しています。


    一般にメゾットの引数にはselfを第一引数として明記する事が決まりです。
    (クラス内に定義された関数をメゾットと呼びます)


    またself.変数名=値とする事で
    クラス内に設置された各関数内でその値を呼び出し
    利用する事ができるようになります。

    上記のコードでは__init__によって引数で与えられた
    文字列”Jake”とint型の値28がそれぞれself.name及びself.age
    に代入されており
    これらの値がクラスのブロック内に設置された関数my_function
    で共有されていることが分かります。

    (self.ageは整数型ですので文字列”My age is”と結合させるには
    str()関数を利用してself.ageを文字列に変換する必要があります。)



    まとめ



    いかがだったでしょうか?
    回を追うごとに内容が濃くなってきていますね。
    レベル的には実践編に近い内容を学びました。


    まずは基本をしっかりと抑え、大きな知識の根幹を作りましょう。
    そうすれば、その枝葉に付随する情報を自らの力で収集する事ができるようになります。


    少しずつ学びの幅を広げていく姿勢が大切です。
    今回は以上にしましょう。
    ではでは



    続編はこちら↓↓





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

    人気記事 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.