Python : 関数の基本操作編

TwitterFacebookHatena
  • 公開:2021-10-1
  • 更新:2023-10-26
  • 文章量:5431
  • Python

TL;DR

関数は処理をまとめた再利用可能なコードである。関数は他のコードから切り離され、名前を付けられたコードである。

関数のポイント

  • Python では関数もオブジェクト
  • 関数を定義するには def と入力する
  • 関数名の先頭は英字か_ を使う
>>> def h():
...     print('hello')
...
>>> type(h)
<class 'function'>

Python の関数には、3 つの特徴がある。

  • 名前を持つ
  • 手続きの流れを含む
  • 返り値(return で定義)

関数の基本形

def hoge():
    print('hello')

# 関数呼び出し
hoge()
# hello

関数名には小文字とアンダースコアを使う。引数のない呼び出しはエラーになる。

実引数と仮引数

関数定義時に使う引数を仮引数と呼び、関数呼び出し時に渡す引数を実引数と呼ぶ。関数の外からは実引数、関数の中では仮引数。

実引数を渡して関数を呼び出すとき、それらの値は関数内の対応する仮引数にコピーされる。

実引数が不足したり多かったりするとエラーになる。変数に関数を代入することもできる。

def w():
    print('word')

h = w() # 変数に関数を代入
h
# word
def h(name):
    print('hello ' + name)

h('john')
# hello john

位置引数

先頭から順に対応する位置の仮引数にコピーされる。

def menu(a, b, c):
    """位置引数"""
    return {'A': a, 'B': b, 'C': c}
menu('X', 'Y', 'Z')
# {'A': 'X', 'B': 'Y', 'C': 'Z'}

仮引数にデフォルト値

関数の呼び出しには、デフォルト値を持たせられる。引数名=デフォルト値 といったように指定する。

def h(w='word'):
    print(w)

h()
# word

引数を渡すと、その値が利用される。

def h(w='word'):
    print(w)

h('change')
# change

キーワード引数

キーワード引数は関数の呼び出しで、仮引数名を指定して渡す実引数である。キーワード引数(実引数にセット) 呼び出し時の順番は呼び出し結果に影響しない。

def h(a, b):
    return a

h(b=1, a=2) # キーワード引数
# 2

return 文

return 文を使うと、関数の戻り値を指定できる。return 文が実行されると、そこで処理が終了する。

def i(plus):
    return plus + 1

i(2)
# 3

def h(n = 'guest'):
    if n == 'guest':
        return '名前を教えてください'

h()
# '名前を教えてください'

複数の引数をセットできる。以下、BMI を計算させてみる。

def bmi(h,w):
    return w / (h/100) ** 2

bmi(174, 62)
# 20.478266613819528

return がない場合

return 文がない場合は None が返される。return 文が実行されない関数は保守性が低くなるので、常に return 文が実行されるように戻り値を書くべきである。

def no_r():
    pass

print(no_r())

# None

可変長引数

可変長引数は、数が決まっていない引数を渡す方法である。関数の引数が任意の個数となっている。 可変長の引数を受け取る関数は、仮引数名に * アスタリスクをつけて定義する。 仮引数に割り当てられなかった位置引数をタプルで受け取る。

# 慣例として *args と記述することが多い。
def h(*args):
    for i in args:
        print(i)

h('one', 'two', 'three')

# one
# two
# three

可変長のキーワード引数

アスタリスクを 2 つ使うことで、キーワード引数を 1 つの辞書にまとめることができる。可変長のキーワード引数を受け取る関数は、仮引数名にアスタリスクを 2 つ付けると定義できる。

# 慣例として **kwargs と記述することが多い。
def h(**kwargs):
    print(kwargs)

h(a=10, b=20, c=30)
# {'a': 10, 'b': 20, 'c': 30}

キーワード専用引数

引数に単独の * を付けた場合、* 以降の引数は、キーワード引数という形でしか渡せない。

def h(a, *, b):
    print(f'{a} {b}')

h(1, b=2)

# 1 2

引数リストのアンパック

*演算子は、リストや辞書に格納された値を引数に渡す機能である。

def print_page(one, two, three):
    print(one)
    print(two)
    print(three)

contents = ['a', 'b', 'c']
print_page(*contents)

# a b c

**演算子を使うと、辞書に格納している値をキーワード引数として渡す。

def print_page(one, two, three):
    print(one)
    print('2番目 - ', two)
    print('3番目 - ', three)

dic = {'two' : 2, 'three' : 3}
print_page('1番目', **dic)

# 1番目
# 2番目 -  2
# 3番目 -  3

関数内関数

関数の中に関数を入れることも可能である。外側の関数から内側の関数を呼び出す。

関数内関数はクロージャ(ほかの関数によって動的に生成される関数)として機能し、自分の外で作られた変数の値を変更できる。

def out(a, b):
    print('関数を呼び出します')
    def inner(c, d):
        return c + d
    return inner(a, b)
out(2, 3)

# 関数を呼び出します
# 5

ラムダ関数

ラムダ関数は、一行で表現される無名関数である。無名関数とは、関数が必要なときにその場で定義する使い捨て関数である。無名が故に「関数名を考える必要がない」というメリットもある。

どんなときに使われるのかというと、関数を「引数」として受け取る関数を呼び出すときなど。

ラムダは 0 個以上のカンマ区切りの実引数を取り、後ろにコロンをつけ、関数定義をする。lambda では丸括弧を使わない。

無名関数は、関数の引数として関数オブジェクトを渡すときに利用される。式はそのまま返されるので、return 文は不要である。

lambda 引数1, 引数2 : 戻り値
b = lambda a : a + 1

b(2)

# 3

b = lambda a, b : a + b

b(1,2)

# 3

関数を引数として呼び出す。

n = ['Python', 'Rust', 'Go']
f = filter(lambda i: len(i) == 4, n)
list(f)

# ['Rust']

ジェネレーター関数

return を yield に変えれば、複数の値を一つずつ作り出すジェネレーターになる。ジェネレーター関数を使うことにより、yeild のところまで処理を進め一旦停止する。そして任意のタイミングで処理を再開することができる。

参考 : yield を使う関数をジェネレーター関数、内包表記を使うものをジェネレーター式という

次のコードは、next 関数が呼ばれるたびに、関数の中の処理が次の yield まで進んでいることを示している。値がなくなると例外 StopIteration が返る。

def g(n):
     while n:
        yield n
        n -= 2

a = g(100)
next(a) # 100
next(a) # 98
next(a) # 96

デコレータ

ソースコードを書き換えずに、既存の関数に変更を加えたいことがある。デコレータは、既存関数に対してコードの変更なしに処理を追加する関数である。

参考 : デコレータは既存の関数に機能を追加する関数

def a(x):
    def new_a():
        print('before')
        x()
        print('after')

    return new_a

@a
def b():
    print('middle')

b()

# before
# middle
# after

型ヒント

関数には、アノテーション(タグ付け)を用いて型ヒント(関数の引数と戻り値に型情報を付ける機能)を追加できる。しかし、実行時に型チェックが行われるわけではない。あくまでも注釈であり、コードの保守性を向上させるために付与するのである。

使い方

  • :の横に型を指定
  • -> の横は返り値の型を指定
def w(a:int) -> int:
    return a

w(3)
# 3
def greeting(name: str) -> str:
    return 'Hello ' + name

再帰

関数が自分自身を呼び出すことを再帰という。再帰はリストのネストなど、平坦ではないデータを処理するときに役立つ。

def flat(x):
    for i in x:
        if isinstance(i, list):
            for i_in in flat(i):
                yield i_in
        else:
            yield i

x = [1, 2, [3, 4, 5], [6, [7, 8, 9]]]
list(flat(x))

# [1, 2, 3, 4, 5, 6, 7, 8, 9]

Docstring

関数には Docstring を記述することができる。Docstring は、コメントと同じように何を書いてもよいが、エディタでヒントを出したときに理解の手助けとなるように、引数・戻り値・関数の概要を記述するとよい。

def print_page(one, two, three):
    """関数の概要

    引数:
        引数の説明
    戻り値:
        戻り値の説明

    """
    print(one)
    print(two)
    print(three)

Google の Python Docstrings の例が記述してあるExample Google Style Python Docstrings — napoleon 0.7 documentationが、参考になる。

Docstring は複数行にまたがることがあり、段落が作られる。段落の題名:の後にインデントされたテキストのブロックが続く。

def function_with_types_in_docstring(param1, param2):
    """Example function with types documented in the docstring.

    `PEP 484`_ type annotations are supported. If attribute, parameter, and
    return types are annotated according to `PEP 484`_, they do not need to be
    included in the docstring:

    Args:
        param1 (int): The first parameter.
        param2 (str): The second parameter.

    Returns:
        bool: The return value. True for success, False otherwise.

    .. _PEP 484:
        https://www.python.org/dev/peps/pep-0484/

    """

Python : 関数の基本操作編