せっかくなのでPythonの引数について復習する

# はじめに
[JavaScriptのそれについて書かれた記事](https://qiita.com/Yametaro/items/21f7b1a4ae09f16f323e)のコメント欄が大変興味深かったので、現在業務でメインに使用しているPythonについても改めて認識を整理しようと思いこの記事を書きました。

# 結論：Pythonは値渡し？参照渡し？
**オブジェクトへの参照渡し**です。
公式ドキュメントにもそう書いてあります。
https://docs.python.org/ja/3/tutorial/controlflow.html#defining-functions

>
関数を呼び出す際の実際の引数 (実引数) は、関数が呼び出されるときに関数のローカルなシンボルテーブル内に取り込まれます。そうすることで、引数は 値渡し (call by value) で関数に渡されることになります (ここでの 値 (value) とは常にオブジェクトへの 参照(reference) をいい、オブジェクトの値そのものではありません) [1]。
･･･
脚注[1] 実際には、オブジェクトへの参照渡し (call by object reference) と書けばよいのかもしれません。というのは、変更可能なオブジェクトが渡されると、関数の呼び出し側は、呼び出された側の関数がオブジェクトに行ったどんな変更 (例えばリストに挿入された要素) にも出くわすことになるからです。

なるほどな～。うんうん

# 極度説明(しなさい)
そもそもPythonは変数がオブジェクトへの参照なので、変数である仮引数は当然オブジェクトへの参照を持つでしょっていうシンプルな話なのですが、さすがにこの公式ドキュメントを読んで納得できる人間はいないと思うので順を追って説明します。

## Pythonの変数ってなんだ
下の関数を見てください。

```python
def Hoge():
    x = 'hoge'
    x = x + 'fuga'
```
まず、関数Hoge(抽象化して言えばfunctionクラスのインスタンス)は内部に名前とその名前が指すオブジェクトへの参照とのkey-valueペアを持つ**シンボルテーブル**と呼ばれる辞書を持っています。
2行目では、リテラルが値hogeを持ったstr型のオブジェクトを作成し、作成されたオブジェクトへの参照が関数Hogeのシンボルテーブルにxという名前で登録されます。これがPythonにおける**変数**と呼ばれるものの正体です。
最後に3行目ですが、まず右辺の式では+演算子によってx('hoge')と'fuga'を結合した新しいstr型オブジェクトが作成されます。そして、シンボルテーブルのkey: xのvalueがこの新しいオブジェクトへの参照で上書きされます。

これが正しいことを確認するために、2行目の後と3行目の後でそれぞれxのidを調べてみましょう。

```python:test
def Hoge():
    x = 'hoge'
    print(id(x))
    x = x + 'hoge'
    print(id(x))

Hoge()
```
```python:result
43412704
30974448
```

というわけで、xという名前の示すオブジェクトが再代入(再束縛)によって変わっていることが確認できました。

## 仮引数 is 変数
仮引数とは、関数が呼び出される際に引き渡された値(実引数)を受け入れるための**変数**です。変数名だけが先に用意されていると思ってください。

下のプログラムを実行してみましょう。

```python:test
def Hoge():
    x = 'hoge'
    print(id(x))
    Fuga(x)

def Fuga(y):
    print(id(y))

Hoge()
```
```python:result
43281408
43281408
```

ここで大事なのは、関数Hogeのシンボルテーブルに存在するxのvalue: 'hoge'(id:43281408)への参照を、関数Fugaのシンボルテーブルにyという名前で**コピー**しているということです。
何回か推敲したんですがうまいこと日本語にできなかったので実際のシンボルテーブルを見てください。

```python:test
def Hoge():
    x = 'hoge'
    print(f'{locals()} / x id: {id(x)}')
    Fuga(x)

def Fuga(y):
    print(f'{locals()} / y id: {id(y)}')

Hoge()
```
```python:result
{'x': 'hoge'} / x id: 43281408
{'y': 'hoge'} / y id: 43281408
```

id: 43281408への参照が関数Hogeと関数Fugaのシンボルテーブル**それぞれ**に存在することが確認できました。

## 話はどこまでも変数について
```python:test
def Hoge():
    x = ['hoge']
    print(f'{locals()} / x id: {id(x)}')
    Fuga(x)
    print(f'{locals()} / x id: {id(x)}')

def Fuga(y):
    print(f'{locals()} / y id: {id(y)}')
    y[0] = 'fuga'
    print(f'{locals()} / y id: {id(y)}')
    y = ['piyo']
    print(f'{locals()} / y id: {id(y)}')

Hoge()
```
```python:result
{'x': ['hoge']} / x id: 30237384
{'y': ['hoge']} / y id: 30237384
{'y': ['fuga']} / y id: 30237384
{'y': ['piyo']} / y id: 41879688
{'x': ['fuga']} / x id: 30237384
```

ここまで読めばこの結果についてもすんなり受け入れられると思います。
id: 30237384は`y[0] = 'fuga'`で値を変更されていますが、`y = ['piyo']`は新しいオブジェクト(id: 41879688)で関数Fugaのシンボルテーブルを書き換えるため、id: 30237384に影響を及ぼさないのです。

**で**、この挙動なんですが。どこかで見たことありませんか？

```python:test
def Hoge():
    x = ['hoge']
    y = x
    print(f'{locals()} / x id: {id(x)} y id: {id(y)}')
    y[0] = 'fuga'
    print(f'{locals()} / x id: {id(x)} y id: {id(y)}')
    y = ['piyo']
    print(f'{locals()} / x id: {id(x)} y id: {id(y)}')

Hoge()
```
```python:result
{'x': ['hoge'], 'y': ['hoge']} / x id: 5989064 y id: 5989064
{'x': ['fuga'], 'y': ['fuga']} / x id: 5989064 y id: 5989064
{'x': ['fuga'], 'y': ['piyo']} / x id: 5989064 y id: 35981384
```

そうです。別に引数じゃなくても同じなのです。なので冒頭の

* Pythonはオブジェクトへの参照渡し

という覚え方にはあまり意味がなく、

* Pythonの変数はオブジェクトへの参照に名前をバインドしたもの
* バインドの一覧であるシンボルテーブルは関数それぞれが持つ
* 仮引数は変数

という3段階を理解していることが大事なんじゃないかなあと個人的には思っています。というか突然「オブジェクトへの参照渡し」とか言われても**意味分からん**って。

# 演習問題
最後に1つクイズを出して終わろうと思います。以下のプログラムの出力はどうなるでしょうか？

```python:test
def Hoge():
    x = ['hoge']
    Fuga(x)
    print(x)

def Fuga(y):
    y = y.append('fuga')
    y = ['piyo']

Hoge()
```

<details><summary>答え</summary><div>

```python:result
['hoge', 'fuga']
```
</div></details>