sec03 - 【Python入門】引数・デフォルト値・可変長引数を完全マスターする
スポンサーリンク

1. 引数の基本

関数には「引数(argument)」を渡すことができます。引数とは、関数に渡すデータのことで、同じ関数をさまざまな値で再利用できるようにするために使います。関数を定義する側では「パラメータ(parameter)」として受け取り、呼び出し側で実際の値を渡します。

💡 サンプルコード

def greet(name):
    print(f'こんにちは、{name}さん!')

greet('Alice')

🖥️ 実行結果

こんにちは、Aliceさん!

このコードでは、greet関数が nameというパラメータを受け取り、その値を文字列に結合して表示しています。
greet("Alice")と呼び出すと、nameに "Alice" が代入されます。このように、引数を変えるだけで同じ関数を何度も使えるのが利点です。

💡 サンプルコード②:同じ関数を再利用

greet('田中')
greet('佐藤')

🖥️ 実行結果

こんにちは、田中さん!
こんにちは、佐藤さん!

引数を変えるだけで、同じ関数を異なるデータで呼び出せます。これにより、関数は汎用性を持った便利な道具として使えるようになります。

2. 複数の引数(位置引数)

2-1. 複数の位置引数の基本

関数には複数の引数を渡すことができます。複数の値をカンマ,で区切り、記述していきます。

引数は、関数で定義したパラメータの順番通りに値が渡されます。このような渡し方の引数の事を『位置引数』と言います。引数の順序を間違えると結果も変わります。

💡 サンプルコード①:複数の引数を受け取る

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

add(3, 5)

🖥️ 実行結果

8

関数 addabという2つのパラメータを受け取ります。
add(3, 5)と呼び出すと、a=3b=5が代入され、足し算して出力されます。

💡 サンプルコード②:順序を間違えると結果が変わる

def divide(dividend, divisor):
    print(dividend / divisor)

divide(10, 2)
divide(2, 10)

🖥️ 実行結果

5.0
0.2

位置引数は順番に意味があります。割り算の場合、dividenddivisorに渡す値の順序を入れ替えると、計算結果も変わります。関数を呼び出す際には、引数の順序に注意が必要です。

2-2. 位置引数の注意事項

関数が位置引数を受け取る場合は、呼び出し側は、関数が要求する数の引数を渡す必要があります。引数の数が少なかったり多すぎる場合はエラーになります。

スポンサーリンク

3. キーワード引数

キーワード引数を使うと、引数名を指定して値を渡せます。順序に依存せず、可読性も向上します。

💡 サンプルコード①:キーワード引数

def divide(dividend, divisor):
    print(dividend / divisor)

divide(divisor=2, dividend=10)
divide(dividend=10, divisor=2)

🖥️ 実行結果

5.0
5.0

キーワード引数を使うと、代入先が固定されるため、引数の順序を入れ替えても同じ結果が出力されます。

4. デフォルト引数(default argument)

4-1. デフォルト引数の基本

関数にあらかじめ初期値(デフォルト値)を設定すると、呼び出し時にその引数を省略できます。省略された場合、デフォルト値が自動的に使われます。

💡 サンプルコード①:単一のデフォルト値

def greet(name='ゲスト'):
    print(f'ようこそ、{name}さん!')

greet()
greet('田中')
greet(name='山田')

🖥️ 実行結果

ようこそ、ゲストさん!
ようこそ、田中さん!
ようこそ、山田さん!

デフォルト値は引数が省略された場合のみ使われます。
greet()では "ゲスト" が使われ、greet('田中')では渡された値 "田中" が優先されます。

デフォルト引数が定義された関数を呼び出す時の引数の渡し方は、大きく3つの方法があります。

  • 引数を渡さない (デフォルト値が使用されます)
  • 位置引数のように、値のみ渡す
  • name='山田'のように、キーワード引数として渡す

💡 サンプルコード②:複数のデフォルト値

def connect(host='localhost', port=8080):
    print(f'接続先:ポート番号 = {host}:{port}')

connect()
connect('example.com', 3000)
connect('example.com')
connect(port=3000)
connect(host='example.com')
connect(host='example.com', port=3000)

🖥️ 実行結果

接続先:ポート番号 = localhost:8080
接続先:ポート番号 = example.com:3000
接続先:ポート番号 = example.com:8080
接続先:ポート番号 = localhost:3000
接続先:ポート番号 = example.com:8080
接続先:ポート番号 = example.com:3000

複数のデフォルト値を持つ関数を呼び出すときの、引数についての注意事項は次の通りです。

  • [5行目] ('example.com', 3000)のように引数を渡す場合、関数で定義された順序通りに値が代入されます。
  • [6行目] ('example.com')のように引数を渡すと、最初のパラメータのhost'example.com'が代入されます。portはデフォルト値の8080が使用されます。
  • [7行目] portのみ引数を渡す場合は、port=3000のようにキーワード引数として渡します。connect(3000)のように記述すると、host3000が代入されてしまいます。キーワード引数を使用しない場合、値は位置引数のように定義された順番に代入されることに注意しましょう。
  • [8行目] host='example.com'のようにキーワード引数を使用することは可能です。
  • [9行目] 全ての引数にキーワード引数を使用しても問題ありません。((host='example.com', port=3000))

4-2. 可変オブジェクトのデフォルト値問題

💡 サンプルコード③:可変オブジェクトのデフォルト値問題

def add_item(item, item_list=[]):
    item_list.append(item)
    print(item_list)

add_item('A')
add_item('B')

🖥️ 実行結果

['A']
['A', 'B']

デフォルト値としてlistを使うと、関数定義時に1回だけ生成されたlistが再利用されます。引数を省略して呼び出すたびに同じlistが使われるため、要素が意図せず増えてしまう問題があります。これは、list以外のデータ構造にも当てはまります。

安全にするには、デフォルト値をNoneにしておき、引数が渡されなかったときに関数の中で新しいlistを作る方法があります。

次のコードの場合、item_listNoneだったとき(引数としてlistが渡されなかったとき)、関数の中で新しいlistを作ります。こうすることで、同じlistオブジェクトが再利用されることを防ぐことができます。また、引数にlistが渡された時は、そのlistに対して値が追加されることになります。

def add_item_safe(item, item_list=None):
    if item_list is None:
        item_list = []  # 引数にlistが渡されなかったときは、ここで新しく作られる
    item_list.append(item)
    print(item_list)

add_item_safe('A')
add_item_safe('B')
add_item_safe('C', ['引数として渡されたlist'])

🖥️ 実行結果

['A']
['B']
['引数として渡されたlist', 'C']

5. 可変長引数 *args

*argsのように引数名の前にアスタリスク*を付けると、任意の個数の位置引数を受け取れるようになります。

💡 サンプルコード

def add_all(*numbers):
    print(f'numbers = {numbers}')
    print(f'引数の合計値 = {sum(numbers)}')

add_all()
add_all(100)
add_all(1, 2, 3)
add_all(5, 10, 15, 20)

🖥️ 実行結果

numbers = ()
引数の合計値 = 0
numbers = (100,)
引数の合計値 = 100
numbers = (1, 2, 3)
引数の合計値 = 6
numbers = (5, 10, 15, 20)
引数の合計値 = 50

*argsで受け取った値はtupleとしてまとめられるため、任意の個数(0個も含む)の引数に対応できます。関数の中の処理は、tupleとして値を受け取ることを前提にコードを書きましょう。

6. 可変長キーワード引数 **kwargs

**kwargsのように引数名の前にアスタリスクを2つ**付けると、任意の個数のキーワード引数を受け取れるようになります。

💡 サンプルコード

def show_info(**info):
    print(info)

show_info(name='Alice', age=25)
show_info(job='Engineer', country='Japan')

🖥️ 実行結果

{'name': 'Alice', 'age': 25}
{'job': 'Engineer', 'country': 'Japan'}

**kwargsdictとしてまとめられるため、自由にキーワード引数を渡せます。

7. ミュータブルとイミュータブル

listやdictなどのミュータブル(変更可能な)オブジェクトは関数内で変更すると呼び出し元にも影響します。一方、数値や文字列のようなイミュータブル(変更不可な)オブジェクトは影響しません。

💡 サンプルコード①:ミュータブル

def add_element(lst):
    lst.append(4)
    print(f'lst = {lst}')

my_list = [1, 2, 3]
add_element(my_list)
print(f'my_list = {my_list}')

🖥️ 実行結果

lst = [1, 2, 3, 4]
my_list = [1, 2, 3, 4]

呼び出し元のlist(my_list)が関数内で変更され、その影響が残ります。

💡 サンプルコード②:イミュータブル

def add_one(n):
    n += 1
    print(f'n = {n}')

x = 10
add_one(x)
print(f'x = {x}')

🖥️ 実行結果

n = 11
x = 10

数値はイミュータブルなので、関数内で変更しても(変数n)、呼び出し元(変数x)には影響しません。

8. 引数の順序のルール

Pythonの関数では、引数の種類によって順序ルールがあります。順序を守らないとエラーになります。

def func(a=1, b):
    pass

🖥️ 実行結果

SyntaxError: parameter without a default follows parameter with a default

デフォルト値のある引数の後に、デフォルト値のない引数を置くことはできません。

9. 引数のアンパック

listやdictをアンパックして引数として渡すことができます。

listをアンパックして、各位置引数へ代入したい場合は、アスタリスク*を先頭に付けます。

def add(a, b, c):
    print(a + b + c)

numbers = [1, 2, 3]
add(*numbers)
6

イメージとして、add(*[1, 2, 3])add(1, 2, 3)のように展開され、関数が実行されます。

dictをアンパックして、キーワード引数として代入したい場合は、アスタリスク2個**を先頭に付けます。

def greet(name, age):
    print(f'{name}さんは{age}歳です。')

person = {'name': 'Alice', 'age': 25}
greet(**person)
Aliceさんは25歳です。

イメージとして、greet(**{'name': 'Alice', 'age': 25})greet(name='Alice', age=25)のように展開され、関数が実行されます。

10. 引数の組み合わせ例

def introduce(name, age=18, *hobbies, **profile):
    print('名前:', name)
    print('年齢:', age)
    print('趣味:', hobbies)
    print('プロフィール:', profile)

introduce('Alice', 25, '読書', '旅行', country='Japan', job='Engineer')
名前: Alice
年齢: 25
趣味: ('読書', '旅行')
プロフィール: {'country': 'Japan', 'job': 'Engineer'}
  • 位置引数 name: 最初の"Alice"がnameに割り当てられます。
  • デフォルト引数 age: 値25が渡されているので、デフォルト値18は無視されます。
  • *args hobbies: 残りの位置引数"読書"と"旅行"がtupleとしてまとめられます。
  • **kwargs profile: 残りのキーワード引数country='Japan'job='Engineer'がdictとしてまとめられます。

このように、引数の割り当て順序は 位置引数 → デフォルト引数 → *args → **kwargsで決まります。

スポンサーリンク