Pythonにおける「プライベート」変数の仕組み:ダブルアンダースコア(__)と名前マングリング

JavaやC++などの言語には、クラスの外部からのアクセスを禁止する「アクセス修飾子(private, protected, public)」が存在します。一方、Pythonには言語仕様として厳密な意味での「プライベート(外部からアクセス不可能)」な変数は存在しません。

しかし、Pythonでも変数の前にアンダースコアを2つ付ける(__)ことで、外部から擬似的に隠蔽する機能が提供されています。

この記事では、__ を使った変数の定義方法と、その背後にある「名前マングリング(Name Mangling)」という仕組みについて解説します。

目次

__(ダブルアンダースコア)による変数の隠蔽

クラス内で、変数名やメソッド名の先頭に __(アンダースコア2つ)を付けると、そのメンバはクラスの外部から直接参照できなくなります。

例として、データベースの接続情報を管理するクラスを作成します。接続パスワードのような重要な情報は、外部から不用意に参照されたくないデータです。

class DatabaseConnector:
    def __init__(self, user, password):
        self.user = user
        # 先頭に __ を付けてプライベート変数とする
        self.__password = password

    def __connect_internal(self):
        """内部的な接続処理(プライベートメソッド)"""
        print(f"ユーザー {self.user} でパスワード {self.__password} を使用して接続しました。")

    def execute(self):
        """外部公開するメソッド"""
        print("処理を開始します。")
        # クラス内部からはプライベートメンバにアクセス可能
        self.__connect_internal()
        print("処理が完了しました。")

# インスタンス化
db = DatabaseConnector("admin", "secret1234")

# 公開メソッド経由での実行は成功する
db.execute()

実行結果:

処理を開始します。
ユーザー admin でパスワード secret1234 を使用して接続しました。
処理が完了しました。

クラス内部のメソッド(execute)からは、__password__connect_internal に問題なくアクセスできています。

外部からアクセスした場合のエラー

では、クラスの外部からこれらのメンバに直接アクセスを試みるとどうなるかを確認します。

# 外部からプライベート変数にアクセスしようとする
try:
    print(db.__password)
except AttributeError as e:
    print(f"エラー発生: {e}")

# 外部からプライベートメソッドを呼び出そうとする
try:
    db.__connect_internal()
except AttributeError as e:
    print(f"エラー発生: {e}")

実行結果:

エラー発生: 'DatabaseConnector' object has no attribute '__password'
エラー発生: 'DatabaseConnector' object has no attribute '__connect_internal'

このように、外部からは「そのような属性(attribute)は存在しない」というエラー(AttributeError)が発生し、隠蔽されているように見えます。

仕組み:名前マングリング (Name Mangling)

Pythonがこの隠蔽を実現している仕組みは非常に単純です。実は、アクセスを禁止しているのではなく、**「変数名を勝手に書き換えている」**だけなのです。これを「名前マングリング」と呼びます。

__ で始まるメンバは、内部的に _クラス名__変数名 という名前に変換されています。

dir() 関数を使って、インスタンスが持っている属性の一覧を確認すると、その実態が見えます。

# インスタンスの属性一覧を表示
print(dir(db))

実行結果(一部抜粋):

['_DatabaseConnector__connect_internal', '_DatabaseConnector__password', 'execute', 'user', ...]

リストの中に _DatabaseConnector__password という名前が見つかります。これが __password の正体です。

マングリングされた名前でのアクセス

つまり、変換された名前を使えば、外部からでもアクセス可能です。

# マングリングされた名前を使って無理やりアクセスする
print(f"裏口からのアクセス: {db._DatabaseConnector__password}")

実行結果:

裏口からのアクセス: secret1234

このように、Pythonのプライベート変数は「絶対にアクセスできない」ものではなく、「アクセスしにくくされている(意図しない衝突を防ぐ)」ための機能です。

シングルアンダースコア (_) との使い分け

Pythonには、アンダースコア1つ(_)で始まる変数(例: _variable)を使う慣習もあります。

  • _variable (シングルアンダースコア): 「これは内部用の変数なので、外部から触らないでください」という開発者間の紳士協定です。機能的なアクセス制限や名前マングリングは行われません。
  • __variable (ダブルアンダースコア): 名前マングリングが行われます。主に、クラスを継承した際に、親クラスと子クラスで変数名が衝突するのを防ぐために使用されます。

基本的には、単に「非公開にしたい」という意図であればシングルアンダースコア(_)を使用し、クラスの継承構造における名前の衝突を厳密に回避したい場合にのみダブルアンダースコア(__)を使用するのが、Pythonにおける一般的な設計指針です。

まとめ

  • 変数名やメソッド名の先頭に __ を付けると、外部から直接アクセスできなくなります。
  • これは「名前マングリング」により、名前が _ClassName__MemberName に変換されるためです。
  • セキュリティ的な意味での完全な隠蔽ではありません。
  • 一般的な「非公開」の意思表示には、シングルアンダースコア(_)の使用が推奨されます。
よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

この記事を書いた人

私が勉強したこと、実践したこと、してることを書いているブログです。
主に資産運用について書いていたのですが、
最近はプログラミングに興味があるので、今はそればっかりです。

目次