【初心者向け】関数とは何か?

関数とは

関数とはあるデータを受け取り、定められた独自の処理を実行し、その結果を返す命令のことです。
関数には2種類あり、1つ目は独自関数、2つ目は標準関数(組み込み関数)です。
独自関数は、プログラマーが変数を作るのと同じように自由に名前と処理を考え、プログラマーが作ることもできます。
関数を組み合わせることで、プログラムを効率的に作ることができます。
標準関数は、Pythonが最初から用意してある関数です。
標準関数は、print()やlen()、input()などを指します。
プログラミングの世界では、自由に関数を定義し、作った関数を何度も呼び出して使うことができるという特徴があります。
この章では主に独自関数の文法に重点を置き、説明していきます。

関数を使うメリット・デメリット

まず、メリットから説明します。
ここでは大きく2つ紹介します。
1)コードがわかりやすくなる
関数を使うことのメリットとして、まずコードがわかりやすくなります。
各機能をまとめておくことで見やすくなるだけではなく、デバッグ作業も効率良くなります。
2)関数でコードの重複を減らすことができる。
コードの保守性が上がります。
次は、デメリットですが、細かい説明をするといくつかピックアップできますが、
そこまでデメリットというデメリットはあまりあげられません。
ですので、積極的に関数を作って使う習慣を作って頂けるとプログラミングの幅も広がります。

関数の定義

独自関数の説明として、実際に関数を作っていきます。
(※関数を作ることを関数を定義するなどと言います。)
関数を定義するためには、defというキーワードを使います。

# 注) このコードは構文のため動作しませんので注意してください。
def 関数名():
    # インデント(字下げ)をしっかりするように!
    # 処理 

それでは上記基本構文をベースに、hello!と出力するだけの関数hello関数を作って見ましょう。
helloが関数名で、インデントした行からが、hello関数の処理の定義を記述しています。

# インデントは半角スペース4つ分のことです。
# 以下、hello()関数を定義したサンプルです。

def hello():
    print("hello!")

関数名は変数名と同様に、「予約語」を使わない限り、好きな名前で定義できます。
先ほどのプログラムでは、hello関数を定義しただけですので、呼び出しはしていません。
関数は定義しただけでは実行されず、実際に呼び出すことで使うことができます。

関数を実行(呼び出す)には次のように関数名()とすることで呼び出せます。下記の例では、独自関数hello()を定義し、呼び出す(実行する)にはhello()とします。

# hello関数の定義
def hello():
    print("hello!")

# 関数の呼び出し(実行)
hello() # hello! が出力される

関数の定義では、あくまでも関数を定義しただけですので、処理は行われておりません。
実行するには、関数名()とある行で呼び出し処理が行われています。

関数名

関数名は、開発者が自由に名前をつけることが出来ますが、いくつか注意点があります。
注意点として関数名を定義する際に、予約語などで関数名をつけないことです。
また、Pythonで関数名を独自で定義する際に2単語以上の関数名にする場合は、以下のように、小文字で下線(_)を挟むスタイルが推奨されています。

def lowercase_underscore:
    print("lowercase_underscore")

pass

また、関数は、空のリスト型や、空の辞書型を定義するときのように、中身の処理のない関数を定義することができます。
とりあえず関数を宣言しておいて、関数の処理としては何もしない時は、「pass」を使います。

# 何も処理のないtest関数を定義
def test():
    pass

引数

引数とは、関数を呼び出す際に関数に与える値のことです。
大きく2種類に分けることが出来ます。
1) 仮引数(関数の定義側で受け取る値)
2) 実引数(関数の呼び出し側で与える値)
以下、引数を用いた関数のサンプルプログラムです。

def say_hello(name):
    print("こんにちは" + str(name) + "さん")

say_hello("山田") # こんにちは山田さん

返り値(戻り値)

関数で処理されたデータを呼び出し元に返します。
後ほど、「引数とreturn」にて詳しく見ていきます。

引数とreturn

先ほど、返り値(戻り値)について説明しましたが、return文を実行すると、関数を終了し呼び出し元に戻ります。

return 【返り値(戻り値)】
引数と返り値(戻り値)がある場合の関数の書式を紹介します。
戻り値を省略した場合は、Noneが返り値(戻り値)となります。
また、関数内でreturnが実行された場合も、戻り値はNoneになります。

"""
def 関数名(引数):
    処理
    return 返り値
"""
def adder(a, b):
    return a+b

# 関数内部の処理を変数に保持しておきたい時にreturnは便利です。
value = adder(5,10) # 変数valueに15が代入される



# 先ほどのlen()を用いて返り値(戻り値)に関して説明します。
# 変数dataは、1〜5の5つの要素を持ったリストです。
data = [1,2,3,4,5]

"""
関数len()を実行することで、リストであるdataの要素5が返り値になります。
その返り値5が変数valueに代入されます。
"""
value = len(data)

print(value) # 5

上記len()を図にすると以下のような流れになります。

まず変数dataに[1,2,3,4,5]が代入され、リストとして定義されます。
次に、len()関数によってリストであるdataの要素の数を取得します。
その取得した結果がreturnによって返されており、この返された値が返り値になります。その後、返り値5が変数valueに代入されています。

なぜreturnを使うのか

なぜprint()ではなく、returnを使うのかという点がいまいちピンと来ないことがあります。
この節では、多くのプログラミング初心者がつまずきやすい
なぜ関数内で、print()ではなくreturnを使うのかという違いに説明します。
大前提として、print()とreturnは全くの別物なため、しっかり使い分けが出来るようにする必要があります。
まず、2つの違いとしては次の通りです。
returnは値を返すことが目的
print()は値を出力すること目的
つまり、returnを使うということは値を返す必要がある時に使用するということになります。
具体的にreturnを使った正しい例に関して説明します。
では、まず以下のプログラムを見てください。

def adder1(a, b):
    print(a+b)

def adder2(a, b):
    return a + b

adder1(2, 4)
sum = adder2(2, 4)
print(sum)

このプログラムでは、returnの良さが伝わりにくく、メリットが感じられないと思います。
というのも、adder1のほうが関数の呼び出しが早く出力も関数内部で行うためです。
ですが一般的に使われる関数の使い方の1つに、ある計算結果をreturnで受け取り再度別の関数にその値を渡すといったことを行います。
上記方法ではreturnの良さが伝わりません。
では、イメージとしてreturnの使い方として正しいプログラムを説明しましょう。
以下のサンプルプログラムを読んでください。

def a(a,b):
    return a + b

def b(a,b):
    return a * b

x = a(2,2) # xに4が代入
y = b(x, x)  # 4 * 4

print(y) # 16が出力

関数bのように前の処理結果xをまた関数bの引数で渡しています。
このように、returnを行うことで計算結果を一旦変数に格納することができ、
さらにその値を別の関数に渡して違う処理に繋げることが出来ます。
また、関数に渡すというのはreturnを使う一例ですが、関数に渡さずとも返り値(戻り値)に対して更に何かしらの処理を行うことが出来るということがポイントになります。関数内部で出力(print)するだけであればprint()で出力すれば良いですが、内部にprint関数が無い関数は、処理した結果をreturn(返り値/戻り値)で受け取り、
その値を変数に代入し、また他の関数にその返り値を渡すことで再度別の処理につなげる事が出来るようになります。
前述の通り、returnは値を返すことが目的としているため、関数内部の処理を、関数内部の処理以降のプログラムでも、返り値として受け取った値を使用することが前提となっています。

returnを利用した関数のサンプル

それでは、関数内部にprint()を使わずreturnを使った関数をサンプルとしてみていきましょう。

def power(x):
    return x*x

def absolute(x):
    if (x < 0):
        return -x
    else:
        return x

print(power(10)) # 100
print(absolute(-10)) # 10

引数のデフォルト値

関数では、引数を指定しなかった場合に引数を設定できます。

def func(a, b=5):
    print(a)
    print(b)

func(10,15) # 10と15が出力される
func(3) # 3と5が出力される

ここで、上記プログラムで、b=5となっておりますが、これが引数のデフォルト値です。
引数にはデフォルト値を指定することが出来ます。
この関数は整数値の引数を2つ与えることで、その2つを出力するだけの関数ですが、
もし引数を1つしか渡さなかった場合は、2つ目の値はデフォルト値bが5となっているために、5が出力されます。

さて、下記プログラムに関して考えてみてください。
下記のプログラムを実行すると、[‘python’, ‘Python’]が最後の関数呼び出しで出力されます。

def sample(arg, arg_list=[]):
    arg_list.append(arg)
    print(arg_list)

sample('python')
sample('Python')

Q. この関数を実行する際に、毎回引数に渡した要素だけを返すようにしたいです。
実際に修正するにはどうすれば良いでしょうか??

A. この場合は、次のように修正する必要があります。

def sample(arg):
    arg_list = [] # リストの初期化
    arg_list.append(arg)
    print(arg_list)

sample('python') # ['python']
sample('Python') # ['Python']

上記は、毎回リストを初期化しています。
その後に、引数で渡されたargを初期化した空のリストにappendしています。

関数 変数のスコープ

スコープはかなり重要な部分になります。
今後、プログラミングをしていく上で、大事な考えになりますので、しっかり押さえていきましょう。
ポイントは、変数はどこで作成したかによってスコープ(有効範囲)が違ってきます。

まずは、通常の関数の例を見てみましょう。

def add(x1):
    x2 = 10 # 関数内で変数を作成(ローカル変数)
    result = x1 + x2
    print(result)

add(5) # 5 + 10で15が出力

次に、変数のスコープ(有効範囲)に関するプログラムです。

def add(x1):
    x2 = 10 # 関数内で変数を作成(ローカル変数)
    result = x1 + x2
    print(result)

add(5) # 5 + 10で15が出力
print(x2) # ここでエラーが発生

上記のコードを実行すると、NameError: name ‘x2’ is not definedというエラーが発生します。
これは関数内で定義した変数x2はローカル変数であり、ローカル変数か関数内部だけしか有効ではないため、関数の外側でx2を呼び出すとエラーになってしまいます。

有効な解決手段として関数の外にx2を定義することです。
(※変数のスコープ以外にも、関数内部処理などもわかりやすいよう、修正しています。)

def add(x1,x2):
    result = x1 + x2
    return result

x1 = 5
x2 = 10
result = add(x1, x2) # 5 + 10で15が出力
print(result)

他にも、globalを利用して関数内でグローバル変数を利用するかになります。

グローバル(global)宣言・グローバル変数

関数内でグローバル変数にアクセスするための宣言です。
ローカル変数(関数定義の内部で定義した関数)とグローバル変数(関数定義の外側で定義した変数)があります。

glb = 0

def func1():
    glb = 1

def func2():
    global glb
    glb = 5

print(glb) # 0が出力される
func1()
print(glb) # 0が出力される
func2()
print(glb) # 5が出力される

もう一つ例題を見てみましょう。

var1 = 'グローバル変数'

def sample():
    var2 = 'ローカル変数'
    return (var1, var2)

print(sample())

上記の例は、グローバル変数とローカル変数をそれぞれ宣言しています。
次のサンプルは、関数内からグローバル変数を変更するプログラムです。

var1 = 'グローバル'

def sample():
    global var1

    var1 = 'ローカルに変更されました'

sample()    # グローバル変数var1を関数内部で変更
print(var1) # ローカルに変更されました

まとめ

関数を使うことで、似たような処理を何回も書かずに済みます。
さらに、あるまとまったプログラムを関数として、1つの処理としてまとめておくことで、プログラムの重複を避けることが出来るのでプログラムの可読性が向上します。
関数にすることで、同じ処理を繰り返し定義することなく、容易に再利用することができるようになります。
ほとんどのソフトウェアでは、関数は当たり前のように使うものなので、使いこなせるようにしましょう。

Leave a Reply