[Python]アンダースコアの使い方

# はじめに
Pythonでは変数や関数の命名で（スネークケースの場合）アンダースコア`_`がよく使われると思います。実際、アンダースコアには命名以外にも多くの使い方があります。今回はPythonにおけるアンダースコアの使い方をまとめてみました。

# 変数や関数の命名
Pythonのコーディング規約であるPEP8では、スネークケースが推奨されています。スネークケースとは、`単語をアンダースコアで区切って書く`命名規則のことです。

```python
# 定数名は大文字で書く、アンダースコアで単語を区切る
MY_NAME = "T"

# 変数名は小文字で書く、アンダースコアで単語を区切る
my_age = 29

# 関数名は小文字で書く、アンダースコアで単語を区切る
def my_func(name, age):
    print(f"Hi {name}, you are {age}.")

my_func(MY_NAME, my_age)
```
※（class名など）パスカルケースで書く場合もあります。詳しくは[PEP8](https://pep8-ja.readthedocs.io/ja/latest/)のドキュメントをご参照ください。


# 直前に評価した式の結果
Pythonの対話モードでは、`直前に評価した式の結果`が`_`に代入され、次の式で使用することができます。

```python
>>> 1 + 1
2
>>> _
2
>>> _ + 1
3
```

# 数字のフォーマット
アンダースコアを数値リテラル内に挿入することで、`数字の桁区切りを行う`ことができます。例えば、以下のように記述することで、大きな数字をより見やすくすることができます。

```python
num = 1_000_000_000
```

# 未使用の変数名
for文などで指定した回数でループを`繰り返したいだけ`の場合、i(index)の代わりにアンダースコアを使って、ループの中で数値を使わないことを明示できます。

```python
# 「Hello, world!」を10回出力するだけ
for _ in range(10):
    print("Hello, world!")
```

また、変数のアンパックなどにも使うことができます。

```python
# アンパックでaに1を、bに2を代入する
t = (1, 2, 3, 4)
a, _, b, _ = t
print(a, b) # 1 3
```

# 名前の衝突
変数の末尾にアンダースコアをつけることで`名前の衝突を回避`することができます。例えば予約語を変数名として使いたい場合は、以下のように記述することができます。

```python
if_ = "if statement"
```

# プライベート変数＆メソッド
## シングルアンダースコア
class内の変数やメソッドに`プライベートな意味合いを持たせたい`場合、該当変数やメソッドの前にシングルアンダースコアをつけます。

```python
class MyClass:
    def __init__(self):
        self.public_var = "foo"

        # プライベートな変数であることを示す
        self._private_var = "bar"

    def public_method(self):
        print("This is a public method.")
        
    # プライベートなメソッドであることを示す
    def _private_method(self):
        print("This is a private method.")
```
上記のように記述すると、クラスの外部でアクセスしようとした際に、ほとんどのエディタやIDEでは自動補完から該当変数やメソッドが表示されなくなります。また誤って記述してしまった際にリンターがフラグを立ててくれます。
ただ`強制力はない`ので、外部からアクセスすることを完全に防ぐことはできません。

```python
my_class = MyClass()
print(my_class.public_var)
print(my_class._private_var)
my_class.public_method()
my_class._private_method()
```

```
foo
bar
This is a public method.
This is a private method.
```



## ダブルアンダースコア
ダブルアンダースコアで始まる変数やメソッドは、「名前修飾」という仕組みによってクラスの内部で別の名前に置き換えられます。そのため、外部からアクセスするとエラーが発生します。

```python
class MyClass:
    def __init__(self):
        self.__private_var = "foo"

    def __private_method(self):
        print("bar")
```

```python
my_class = MyClass()
print(my_class.__private_var)
```

```
AttributeError: 'MyClass' object has no attribute '__private_var'
```

```python
my_class.__private_method()
```

```
AttributeError: 'MyClass' object has no attribute '__private_method'
```

※名前修飾の仕組みを回避することができるため、完全なプライベート性は保証されません。また可読性にも影響する可能性があるため、シングルアンダースコアを使ったプライベート化が望ましいという場合も多いかと思います。

# 特殊変数＆メソッド
名前の前後にダブルアンダースコアが付いている変数やメソッドは特殊変数や特殊メソッド（ダンダー）です。これらは、Python言語の様々な機能をサポートするために定義されており、特別な用途に特化した機能を提供します。

## 特殊変数
Pythonには多数の特殊変数がありますが、主要なものを以下に挙げます。
- `__name__`: 現在のモジュールの名前を表す
- `__file__`: 現在のモジュールが定義されているファイルのパスを表す
- `__doc__`: モジュールや関数、クラスなどのドキュメンテーション文字列を表す
- `__builtins__`: 組み込み関数や組み込み定数を含むモジュールを表す
- `__package__`: 現在のモジュールが属するパッケージの名前を表す

例えば、他のモジュールからimportされた場合でなく、モジュールが直接実行された場合にある処理を実行したい場合、以下のように記述できます。

```python
# 直接実行された場合は__name__の値が__main__になる
if __name__ == "__main__":
    pass
```

※他にもありますが、本記事では網羅しません。詳しくは公式ドキュメント等をご参照ください。

## 特殊メソッド
特殊メソッドを定義することで、オブジェクト指向プログラミングにおける様々な機能をサポートすることができます。
例えば、`__init__`は、クラスのインスタンスが生成された際に呼び出されるコンストラクタメソッドです。また、`__str__`は、オブジェクトを文字列に変換するためのメソッドで、print()関数や文字列連結演算子+などで呼び出されます。

```python
class Person:
    def __init__(self, name, age):
        self.name = name
        self.age = age

    def __str__(self):
        return f"Person(name={self.name}, age={self.age})"

person = Person("T", 29)
print(person)
```

```
Person(name=T, age=29)
```

※他にも多数ありますが、本記事では網羅しません。詳しくは公式ドキュメント等をご参照ください。


# まとめ
- 変数や関数の命名にスネークケースを使う場合、アンダースコアで単語を区切る
- 対話モードでは直前に評価した式の結果がアンダースコアに代入される
- 大きな数字をより見やすくしたい場合、アンダースコアを数値に挿入し、数字の桁区切りを行う
- 未使用の変数名や一時変数名にアンダースコアを使える
- 変数の末尾にアンダースコアをつけることで名前の衝突を回避できる
- classの変数やメソッドのプライベート化でアンダースコア（シングルまたはダブル）を使える
- 名前の前後にダブルアンダースコアが付いている特殊変数や特殊メソッドというのがある