SE_BOKUのまとめノート的ブログ

SE_BOKUが知ってること・勉強したこと・考えたことetc

Python3の「関数の引数」の種類と注意点/Python文法

f:id:arakan_no_boku:20190427205325j:plain

 目次

Python3の「関数の引数」の種類と注意点/Python文法

Pythonの関数に与える引数のバリエーションをざっとあげると。

  • 通常の引数(位置引数)
  • キーワード引数(位置引数としても指定可)
  • キーワード専用引数(位置で与えるとエラー)
  • 可変長引数
  • 可変長キーワード引数

があります。

あと、使い方に注意が必要な引数としては。

があります。 

それぞれを個別にみていきます。

通常の引数(位置引数)

引数を定義した位置(順序)にあわせて、値を与えます。

def normal_arg(number):
    print(number ** 2)

 

キーワード引数(位置引数としても指定可)

「keyword=value」の形で、キーワードとデフォルト値を引数として与えます。

def normal_arg(number, first=2, second='答えは'):
    print(second, ':', number ** first)

キーワードを指定して実行時に与えるやり方ができます。

位置引数と異なり、順番を入れ替えても大丈夫です。

normal_arg(3, second='変更後', first=3)

引数の省略もできます。(キーワード引数の初期値でよければ)

normal_arg(3) 

とか

normal_arg(3, first=3) 

普通に「位置引数」のように与えることもできます。

normal_arg(3, 3, '変更後')

キーワード専用引数(位置で与えるとエラー) 

キーワード引数は、位置引数としても与えることができます。

そのため、間違って引数を与えてしまうリスクがあります。

位置引数としての与え方を許さない「キーワード専用引数」があります。

引数に「*」をはさんで、キーワード専用引数の開始位置を示します。

そこから後ろのキーワード引数は「キーワード専用引数」になり、位置引数のような指定の仕方はできなくなります。

def normal_arg(number, *, first=2, second='答えは'):
    print(second, ':', number ** first)

上記の例でいえば、

normal_arg(3, second='変更後', first=3)

normal_arg(3) 

normal_arg(3, first=3) 

はOKですが、以下はNGになります。

normal_arg(3, 3, '変更後')

こんなエラーメッセージがでます。

TypeError: normal_arg() takes 1 positional argument but 3 were given 

可変長引数(位置引数)

引数がいくつになるかわからないケースで、可変長引数を使えます。

*argsのように「*」をつけた引数を定義します。

慣習的に「*args」にしてますが、別に他の名前でもかまいません。

def variable_arg(number, *args):
    result = number
    for i, value in enumerate(args):
        result += value
    print(result)

実行するときは、こんなかんじです。

variable_arg(1, 2, 3, 4, 5)

可変長部分が指定されなければ、空のタプルが渡されます。

可変長引数(キーワード引数)

キーワード引数を可変長で与える場合には、「**」を引数名の頭につけます。

キーワードと値がセットになった辞書で受け渡されます。

例えば。

def variable_arg(number, **kwargs):
    result = number
    for key, value in zip(kwargs.keys(), kwargs.values()):
        print(key, ':', value * number)

実行時の引数の与え方はこんな感じになります。

variable_arg(2, one=1, two=2, three=3, four=4)

実行した結果は。

one : 2
two : 4
three : 6
four : 8

これは便利です。

 イテレータで与えられた引数に注意する

ここで言うイテレータとは、ジェネレータで生成されたものです。

arakan-pgm-ai.hatenablog.com

例えば。

以下の式で生成される「sample_itr」は、Listです。

sample_itr = [n for n in range(1, 6)]

でも。

以下のジェネレータ式だとsample_itrは「イテレータ」になります。

sample_itr = (n for n in range(1, 6))

printすると、上記は

 [1, 2, 3, 4, 5]

 ですけど、後者は

<generator object main.<locals>.<genexpr> at 0x00000297E36EA3B8>

です。 

この2つは同じようにforループの中で使えますが、Listの方は繰り返し使っても同じ結果を取得できるのに対して、イテレータは繰り返し使うことができません。

同じ結果が保証されないからです。

なので、関数の引数に「イテレータ」を渡すのは危険です。

関数の中で引数で渡されたリストをforループで2回使っているかもしれませんから。

なので、ジェネレータ式を使って「イテレータ」として取得したものは、変数の命名規則などで区別できるようにしておかないと、うっかり、なんかの修正で関数の引数として与えてしまうことでバグを埋め込む危険があるということです。

もちろん、これは関数のから「yield」で返される場合も同じです。

以上です。