Phython

【Python】引数の種類
(位置引数・キーワード引数・デフォルト引数)

本記事では、pythonにおけるいろいろな種類の引数についてご紹介していこうと思います。

引数は、関数を扱う上で必須の知識ですが、そんな引数にも様々な種類のものが存在しており、場面によってどの種類の引数を使用したほうが良いのかは変化します。
そのため、どの引数についてもある程度の理解が必要です。

今回は、3つの種類の引数とそれぞれの具体的な使い方を説明しているので、ぜひ参考にしてみてください。

ちなみに、本ブログでは初心者の方でも理解できるように丁寧に説明しているので、全くの初心者という方も安心してください。

また、今回紹介する引数は以下の3つになります。
それぞれの特徴をよく理解しながら記事を読み進めていきましょう。

  • 位置引数
  • キーワード引数
  • デフォルト引数

この記事でわかること

  • 位置引数の使い方
  • キーワード引数の使い方
  • デフォルト引数の使い方

 位置引数について

まず、今回紹介する3つの引数のうちの1つ目である位置引数について説明していこうと思います。

また、基本的な引数の使い方に関しては以下の記事を参考にして下さい。

位置引数とは?

pythonの関数で引数を扱う時、複数の引数を指定することが出来ます。
以下のような感じですね。

<input>

#関数宣言
def menu(food, drink, dessert):
    print("food is", food)
    print("drink is", drink)
    print("dessert is", dessert)

#関数呼び出し
menu("stake", "wine", "cake")

<output>

food is stake
drink is wine
dessert is cake

上記のコードでは、引数foodにstakeを、引数drinkにwineを、引数dessertにcakeを代入してそれぞれを順番に出力していますよね。

では、以下のような場合はどうでしょう。

<input>

def menu(food, drink, dessert):
    print("food is", food)
    print("drink is", drink)
    print("dessert is", dessert)

menu("wine", "cake", "stake")

<output>

food is wine
drink is cake
dessert is stake

関数を呼び出す際に、先ほどと引数の順番を変えてみました。
すると『food is wine』とかいう意味わからない文字列が出力されますよね。

実は、関数を呼び出す際の引数の順番と、宣言時の引数の順番が対応しているのです。
例えば今回のコードですと、関数を呼び出す際の引数として一番初めに『"wine"』を設定しているので、関数宣言時の一番初めの引数『food』の部分に『”wine"』が代入されてしまっているといった感じですね。

このように、順番を意識して引数を渡さなくてはならないのが位置引数です。

位置引数を扱う際は、引数の順番があっているかを確認することを忘れないようにしましょう。

位置引数のタプル化

続いて、位置引数のタプル化についてです。
タプルについてよくわからないという方は、以下の記事を参考にしてください。

では、以下のコードをご覧ください。

<input>

def menu(*args):
    print(args)

menu("wine", "cake", "stake")

<output>

('wine', 'cake', 'stake')

関数呼び出し時に指定した3つの引数がタプルに入っているのがわかるかと思います。
こちらは、関数宣言時の引数を『*args』にすることで実現できます。

しかし、位置引数をタプル化することに何の意味があるのでしょうか?
以下のコードを使って、タプル化するメリットをご紹介します。

<input>

def menu(*args):
    for i in args:
        print(i)

menu("wine", "cake", "stake", "apple", "orange", "grape", "banana")

<output>

wine
cake
stake
apple
orange
grape
banana

上記のように、引数がたくさんある場合って位置引数をそのまま使用しようとすると非常に面倒くさいですよね。
順番を間違えていたら、処理が正常に行えないし、そもそも引数名を書いてコード内にその引数を使った処理を書くのも面倒くさい。

そんな時に使えるのが位置引数のタプル化です。

『menu(*args)』と記入してしまえば、『args』という変数に引数を要素としたタプルが代入されるので、その中身をfor文を用いて出力しているといった感じです。

こうすることで、関数呼び出し時に指定した順番で引数を出力することが出来ます。

ちなみに「for文って何?」「for文についてもっと知りたい」といった方は、以下の記事を参考にして下さい。

 キーワード引数について

続いて、二つ目はキーワード引数です。
先ほどの位置引数との違いに着目しながら使い方を確認していきましょう。

キーワード引数とは?

先ほどの位置引数では、順番を間違えてしまうとプログラムが思ったように動かなかったのですが、キーワード引数を用いることでこのような問題を解決することが出来ます。

では、実際にキーワード引数を使用しているコードを見て使い方を確認していきましょう。

#関数宣言
def menu(food, drink, dessert):
    print("food is", food)
    print("drink is", drink)
    print("dessert is", dessert)

#関数呼び出し
menu(drink="wine", dessert="cake", food="stake")

<output>

food is stake
drink is wine
dessert is cake

このように、関数を呼び出す際に、引数にキーワードを与えてあげると順番を意識する必要なく、引数を使用することが出来ます。

キーワードを付け加えるといった手間は発生しますが、これにより位置間違えによるエラーはなくなります。

位置引数とキーワード引数の併用

実は、位置引数とキーワード引数を併用することも可能です。

<input>

def menu(food, drink, dessert):
    print("food is", food)
    print("drink is", drink)
    print("dessert is", dessert)


menu("stake", dessert="cake", drink="wine")

<output>

food is stake
drink is wine
dessert is cake

上記のコードでいうと、『stake』が位置引数で『cake』と『wine』がキーワード引数ということになりますね。

しかし、以下のように記述するとエラーになります。

def menu(food, drink, dessert):
    print("food is", food)
    print("drink is", drink)
    print("dessert is", dessert)


menu(dessert="cake", "stake", drink="wine")

『stake』という位置引数も、『wine』というキーワード引数も両方とも『drink』に代入しようとしているからですね。
コンピュータはどちらを代入すればよいか判断できないためエラーになってしまいます。

あまりないと思いますが、併用する際は注意しましょう。

キーワード引数の辞書化

続いて、キーワード引数の辞書化についてです。
辞書についてよくわからないという方は、以下の記事を参考にしてください。

では、以下のコードをご覧ください。

<input>

def menu(**kwargs):
    print(kwargs)

menu(food="stake", drink="wine", dessert="cake")

<output>

{'food': 'stake', 'drink': 'wine', 'dessert': 'cake'}

関数呼び出し時に指定した3つの引数が辞書に入っているのがわかるかと思います。
こちらは、関数宣言時の引数を『**kwargs』にすることで実現できます。

しかし、キーワード引数を辞書化することに何の意味があるのでしょうか?
以下のコードを使って、辞書化するメリットをご紹介します。

<input>

def menu(**kwargs):
    for k, v in kwargs.items():
        print(k, v)

menu(food="stake", drink="wine", dessert="cake")

<output>

food stake
drink wine
dessert cake

上記のコードのように、辞書化した引数をfor文を用いて一気に出力することが出来ます。
今回は引数が3つですが、引数を増やしたい場合は、関数を呼び出す際に引数の数を増やしてあげればOKです。
したがって、引数の辞書化を行うことで引数の数を簡単に増やすことが出来ます。

辞書を用いた引数の設定

先ほどは、引数を辞書型に変更してfor文を適用したのですが、それだと引数の数が増えた時に少し見づらくなってしまうと思います。
そのような問題を下記のようなコードで解決してみましょう。

<input>

def menu(**kwargs):
    for k, v in kwargs.items():
        print(k, v)

d = {
    "food": "stake",
    "drink": "wine",
    "dessert": "cake"
}
menu(**d)

<output>

food stake
drink wine
dessert cake

まず、上記コードでは引数を先ほどのように()の中に書いていくのではなくて、辞書型として宣言してあげます。
『d={}』といったところですね。

その後、menuの引数を『**d』としているのですが、これは『d』という辞書を展開するといった意味合いがあります。
要するに、辞書の形ではなく、キーワード引数を指定するときの『food=""...』の形に変更するための命令になっているのです。

なので、今回のコードでは

『①dという辞書を展開したものをmenuの引数とする。
 ②関数menuでは、引数が渡された際にその引数を辞書化して、for文を実行する』といった感じの処理が行われています。

辞書を展開した後、また辞書化するといった処理を行っているので少しわかりにくいかもしれませんが『**』が辞書を展開したり逆に辞書化を行ったりするための命令なんだなという風に覚えていて下さい。

 デフォルト引数について

最後に、3つ目はデフォルト引数についてです。
使用する際の注意点についても触れているので、使い方と合わせて確認していきましょう。

デフォルト引数とは?

デフォルト引数とは、関数宣言時に設定する引数のことです。
今までの位置引数や、キーワード引数は関数呼び出し時に引数を設定していたので、引数を定義する場所が異なるといった感じですね。
実際にコードを用いて使い方を見ていきましょう。

<input>

# 関数宣言
def menu(food="stake", drink="wine", dessert="cake"):
    print("food is", food)
    print("drink is", drink)
    print("dessert is", dessert)

#関数呼び出し
menu()

<output>

food is stake
drink is wine
dessert is cake

上記コードのように、関数宣言時に引数を()内に書いて、関数呼び出し時には引数を指定する必要なく呼び出すことが出来ます。

デフォルト引数は、関数宣言時に引数を書いてしまうためわかりやすいのですが、関数呼び出し時に引数を指定できないため拡張性が低いといったデメリットがあります。

デフォルト引数を使用する際の注意点

デフォルト引数はわかりやすくとても便利な引数ですが、少し注意点があるのでそれについて紹介していきたいと思います。

<input>

def test_function(x, l=[]):
    l.append(x)
    return l

a = test_function(10)
print(a)

<output>

[10]

上記のコードですが、位置引数『x』とデフォルト引数『l』を設定して、空のリストの要素として『x』を追加するといった関数『test_function』を作成しています。

また、その関数に『10』という引数を与えてその結果を表示しているといった感じです。
ここまで何一つ問題はないですよね。
では、さらにコードを追加していきます。

<input>

def test_function(x, l=[]):
    l.append(x)
    return l

a = test_function(10)
print(a)

b = test_function(20)
print(b)

<output>

[10]
[10, 20]

さらにコードを追加して、変数『b』というものを変数『a』と同じように作成しました。

ところが、bの方はaと異なり、余分な要素が追加されているんですね。
これがデフォルト引数を使用する際の注意点です。

では、なぜこのようなことが起きるのでしょうか?

その答えは、リストに値を代入する際に参照渡しが使われているからです。
ここで「参照渡しって何?」という方は、以下の記事を参考にしてみてください。

予期せぬ結果を引き起こした原因

それでは、具体的な原因について説明していきます。

まず、関数『test_function』では、lに初期値『[]』が与えられているため、関数宣言時に空のリストへの住所がlに入っている状態です。

その状態で『a = test_function(10)』の部分で関数test_functionのxの部分に10を入れてリストの要素に10を追加し、その後lをaに代入しています。
その結果、aを表示すると、10のみが入ったリストが出力されているというわけですね。

次に、『b = test_function(20)』を用いて先ほどと同様に、xに20を入れてリストの要素に20を追加し、その後lをbに代入しています。
その結果、bを表示すると、10と20が入ったリストが出力されてしまいます。

このように、lには初めに空のリストへの住所が与えられているため、『l.append()』という風に要素を追加していくとただ後ろに要素が追加されるだけになってしまい、要素が塗り変わらないんですね。

なので、このように予期せぬ結果となってしまったわけです。

では、問題の原因が理解できたところで、解決策を見ていきましょう。

予期せぬ結果の解決方法

以下のようなコードを組んであげれば先ほどの問題を解決することが出来ます。

<input>

def test_function(x, l=None):
    if l is None:
        l = []
    l.append(x)
    return l

a = test_function(10)
print(a)

b = test_function(20)
print(b)

<output>

[10]
[20]

関数の中身を少し変えて、初めにlに初期値を与えずに関数の中でlを作成するといった感じに変更しました。

こうすることで、実行されるたびに、新しいlが作成されて、そこに要素を追加するといった関数が完成します。
デフォルト引数を与えてしまうと、始めて関数が呼び出された時のみ変数に初期値が代入される形になるので、リストを扱う際は注意しましょう。

 まとめ

今回は、位置引数・キーワード引数・デフォルト引数といったいくつかの種類の引数をご紹介してきましたが、いかがだったでしょうか。

引数と一口に言っても、さまざまな種類のものが存在し、どれを使用するかは状況によってまちまちです。

それぞれのメリット・デメリットをよく理解して引数を使いこなせるようになりましょう。

-Phython
-, ,