【Python】 Python ~ 基本編 / 関数・あれこれ ~

■ はじめに

https://dk521123.hatenablog.com/entry/2019/09/22/000000

の続き。

関数の記事が長くなったので、整理して分冊。

また、Pythonの資格の問題ででてきた
デフォルト引数の注意点などを記録。

目次

【0】関数の実体について 
【1】デフォルト引数
 1)デフォルト引数の使用上の注意
【2】 可変長引数
 1)*args (タプル) ... 可変長引数
 2)**kwargs (辞書) ... 名前付き可変長引数
 3)補足:引数のアンパック(展開)
【3】 キーワード引数
 1)キーワード引数
 2)キーワード引数を強制する*
【4】関数の空実装
【5】内部関数(Inner Function)

【0】関数の実体について

* 関数の正体は、オブジェクトである
* 関数を変数に格納して呼び出すことが可能

サンプル

def sample_method(name):
  print("Hello " + name)

func = sample_method
func("Mike") # Hello Mike

【1】デフォルト引数

 * 「引数 = 初期値」にする

サンプル

def sayHello(name="Mike"):
    print("Hello, {}!".format(name))

sayHello()

 出力結果

Hello, Mike!

1)デフォルト引数の使用上の注意

* リストや辞書などのオブジェクトをデフォルト指定した場合、
 そのオブジェクトは関数定義時に生成され、
 2回目以降に呼び出されたら、同じオブジェクトが使われる。

サンプル

def culc(a, b=1, list1=[], list2=[]):
  print(list1)
  print(list2)
  list1.append(a ** 2)
  list2.append(b ** 3)
  return list1, list2

print("Start")
print(culc(1))
print("*******")
print(culc(2, 3))
print("*******")
print(culc(3, 4))
print("*******")
print(culc(4, 5))
print("Done")

出力結果

Start
[]
[]
([1], [1])
*******
[1] << デフォルト値に前回の値が含まれている
[1] << デフォルト値に前回の値が含まれている
([1, 4], [1, 27])
*******
[1, 4] << デフォルト値に前回の値が含まれている
[1, 27] << デフォルト値に前回の値が含まれている
([1, 4, 9], [1, 27, 64])
*******
[1, 4, 9] << デフォルト値に前回の値が含まれている
[1, 27, 64] << デフォルト値に前回の値が含まれている
([1, 4, 9, 16], [1, 27, 64, 125])
Done

 【2】可変長引数

可変長引数には、以下の2種類ある。

1)*args ... 複数の引数をタプルとして受け取る(可変長引数)
2)**kwargs ... 複数の引数を辞書として受け取る(名前付き可変長引数)

1)*args (タプル) ... 可変長引数

 * 「*【引数名】」にする

サンプル

# coding: UTF-8

def say_hello(*names):
    for name in names:
         print("Hello, {}!".format(name))

say_hello("Mike", "Tom", "Sam")

出力結果

Hello, Mike!
Hello, Tom!
Hello, Sam!

2)**kwargs (辞書) ... 名前付き可変長引数

 * 「**【引数名】」にする

サンプル

def function(**key_values):
    for key, value in key_values.items():
         print("Key = {}, Value = {}.".format(key, value))

def main():
    function(A1='Mike', A2='Tom')

if __name__ == '__main__':
    main()

出力結果

Key = A1, Value = Mike.
Key = A2, Value = Tom.

3)補足:引数のアンパック(展開)

* アンパック (unpack)
  ... リストなどの要素を1つ1つ取り出し(展開)、関数に渡す操作

サンプル

list = ["A", "B", "C"]

print(list) # ['A', 'B', 'C']

print(list[0], list[1], list[2]) # A B C
print(*list) # A B C
print(*list, sep=" => ") # A => B => C

参考文献
https://python.keicode.com/lang/list-unpack-asterisk.php

 【3】キーワード引数

1)キーワード引数

* 引数を明示的に指定可能

 サンプル

def say_hello(greeting="Hello", name="Smith"):
    print("{}, {}!".format(greeting, name))     

say_hello()
say_hello(name="Mike")
say_hello(greeting="Good morning", name="Tom")
say_hello(name="Sam", greeting="Good afternoon")

 出力結果

Hello, Smith!
Hello, Mike!
Good morning, Tom!
Good afternoon, Sam!

2)キーワード引数を強制する*

* 以下「(value1, value2, *, arg1=1.0, arg2=0.0):」のように
 アスタリスクを指定すると、アスタリスク以降の引数を指定する場合
 メソッドの使用者側にキーワード引数を強制的に指定させる

https://yohhoy.hatenadiary.jp/entry/20150315/p1

 サンプル (NGケース)

def sample_method(value1, value2, *, arg1=1.0, arg2=0.0):
  print("{} {} {} {}".format(value1, value2, arg1, arg2))

sample_method(1, 2) # ここはOK
sample_method(1, 2, 1) # NG

 出力結果

1 2 1.0 0.0
Traceback (most recent call last):
  File "c:/work/hello/hello.py", line 5, in <module>
    sample_method(1, 2, 1)
TypeError: sample_method() takes 2 positional arguments but 3 were given

 サンプル (OKケース)

def sample_method(value1, value2, *, arg1=1.0, arg2=0.0):
  print("{} {} {} {}".format(value1, value2, arg1, arg2))

sample_method(1, 2) # ここはOK
sample_method(1, 2, arg1=1000) # OK

 出力結果

1 2 1.0 0.0
1 2 1000 0.0

【4】関数の空実装

 * pass を使う

サンプル

# coding: UTF-8

def sayHello2():
    pass

sayHello2()

出力結果

* 実行しても何も起こらない 

【5】内部関数(Inner Function)

* 関数内で関数を定義できる
* nonlocal については、以下の関連記事を参照のこと。

https://dk521123.hatenablog.com/entry/2019/12/12/232749

* 以下のハノイの塔に関する動画でも用いられている

https://www.youtube.com/watch?v=MLronWYaHw8

サンプル

def outer():
  print("外部関数")

  def inner():
    print("内部関数")

  # 外部関数から内部関数を呼び出す
  inner()

outer()

出力結果

外部関数
内部関数

関連記事

Python ~ 基本編 / 関数 ~
https://dk521123.hatenablog.com/entry/2019/09/22/000000
Python ~ 基本編 / 文字列 ~
https://dk521123.hatenablog.com/entry/2019/10/12/075251
Python ~ 基本編 / global・nonlocal ~
https://dk521123.hatenablog.com/entry/2019/12/12/232749
Python ~ 基本編 / yield ~
https://dk521123.hatenablog.com/entry/2021/03/18/000000