Python
 Computer >> コンピューター >  >> プログラミング >> Python

Pythonクラスのプライベート変数とは?ネームマングリングの仕組みとアクセス方法を解説

このチュートリアルでは、Pythonのクラスにおけるプライベート変数について詳しく解説します。

実は、Pythonには他の言語のような厳密な意味でのプライベート変数という概念は存在しません。しかし、多くのPython開発者の間では、「この変数は公開用ではなく内部向けである」ことを示すための命名規則が広く使われています。

その方法とは、変数名をダブルアンダースコア(__)で始めることです。例えば __one__two のように記述することで、その変数を「プライベートである」として扱います(ただし、厳密には完全なプライベートではありません)。

前述の通り、ダブルアンダースコアで始まる名前の変数は完全に非公開になるわけではなく、実際にはアクセスする手段が残されています。ここでは、まずプライベート風の変数を作成する方法を見てから、そのアクセス方法についても確認していきましょう。

クラスとインスタンスの作成

# クラスを作成
class Sample:
    def __init__(self, nv, pv):
        # 通常の変数
        self.nv = nv
        # プライベート変数(厳密にはそうではない)
        self.__pv = pv

# Sampleクラスのインスタンスを作成
sample = Sample('通常の変数', 'プライベート変数')

上記のコードでは、__init__ メソッドの中に2つの変数を定義しました。1つは通常の変数 nv、もう1つはプライベート風の変数 __pv です。それでは、これらの変数にアクセスしてみて、何が起こるか確認してみましょう。

アクセスを試みる例

# クラスを作成
class Sample:
    def __init__(self, nv, pv):
        # 通常の変数
        self.nv = nv
        # プライベート変数(厳密にはそうではない)
        self.__pv = pv

# Sampleクラスのインスタンスを作成
sample = Sample('通常の変数', 'プライベート変数')

# nv にアクセス
print(sample.nv)

# __pv にアクセス
print(sample.__pv)

出力結果

上記のコードを実行すると、次のような出力が得られます。

通常の変数
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
<ipython-input-13-bc324b2d20ef> in <module>
     14
     15 # __pv にアクセス
---> 16 print(sample.__pv)
AttributeError: 'Sample' object has no attribute '__pv'

nv 変数はエラーなく表示されましたが、__pv 変数にアクセスしようとした瞬間に AttributeError が発生しました。

なぜこのようなエラーが起きるのでしょうか?それは、__pv という名前の属性がオブジェクト上に存在しないからです。「では、__init__ メソッド内の self.__pv = pv という文はどうなったのか?」と疑問に思うかもしれませんね。この謎については後ほど説明します。まずは、__pv 変数へアクセスする正しい方法を見ていきましょう。

マングリング後の名前でアクセスする

ダブルアンダースコアで始まるクラス変数には、_クラス名__変数名 という形式の名前でアクセスできます。今回の例であれば、_Sample__pv となります。それでは、この名前を使ってアクセスしてみましょう。

# クラスを作成
class Sample:
    def __init__(self, nv, pv):
        # 通常の変数
        self.nv = nv
        # プライベート変数(厳密にはそうではない)
        self.__pv = pv

# Sampleクラスのインスタンスを作成
sample = Sample('通常の変数', 'プライベート変数')

# nv にアクセス
print(sample.nv)

# _Sample__pv という名前で __pv にアクセス
print(sample._Sample__pv)

出力結果

上記のコードを実行すると、次のような結果が得られます。

通常の変数
プライベート変数

今度は問題なくアクセスできました。では、なぜ変数 __pv の名前が変わってしまったのでしょうか?

ネームマングリング(name mangling)とは

Pythonにはネームマングリング(名前修飾)と呼ばれる仕組みがあります。Pythonは、ダブルアンダースコアで始まる名前の変数を自動的に書き換えます。つまり、ダブルアンダースコアで始まるすべてのクラス変数は、_クラス名__変数名 の形式に変換されるのです。

この仕組みは、クラスのメソッドにも同様に適用されます。次のコードで確認してみましょう。

メソッドの場合の例

class Sample:
    def __init__(self, a):
        self.a = a

    # プライベートメソッド(厳密にはそうではない)
    def __get_a(self):
        return self.a

# Sampleクラスのインスタンスを作成
sample = Sample(5)

# 正しい(マングリング後の)名前でメソッドを呼び出す
print(sample._Sample__get_a())

# 誤った名前でメソッドを呼び出す
print(sample.__get_a())

出力結果

上記のコードを実行すると、次のような結果になります。

5
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
<ipython-input-19-55650c4990c8> in <module>
     14
     15 # 誤った名前でメソッドを呼び出す
---> 16 print(sample.__get_a())
AttributeError: 'Sample' object has no attribute '__get_a'

マングリング後の名前 _Sample__get_a() を使えば正常に呼び出せる一方、元の名前 __get_a() では AttributeError が発生することが分かります。

まとめ

ダブルアンダースコアを使用する目的は、変数やメソッドへのアクセスを完全に禁止することではありません。それは「この変数やメソッドはクラスの内部でのみ使用されることを意図している」という意思表示なのです。外部から直接触ってほしくない内部実装であることを明示することで、コードの可読性と保守性を高め、誤った使い方を防ぐ効果が期待できます。

本チュートリアルについて質問がある場合は、コメント欄でお気軽にお尋ねください。

  1. Pythonでカレンダーを作る方法!calendarモジュールの基本と使い方を解説

    Pythonには、カレンダーを扱うためのcalendarという標準モジュールが組み込まれています。この記事では、calendarモジュールの基本的な使い方について解説していきます。calendarモジュールでは、1週間は月曜日から始まり日曜日に終わります。また、このモジュールはグレゴリオ暦(西暦)に準拠しています。それでは、calendarモジュールの便利なメソッドをいくつか見ていきましょう。年間カレンダーを取得する特定の年のカレンダー全体を取得したい場合は、calendar.calendar(year)クラスのインスタンスを作成し、それを出力します。以下に具体例を示します。コード例# cal

  2. Pythonでクイックソートを実装する方法|初心者向けにサンプルコードを徹底解説

    この記事では、クイックソート(QuickSort)のアルゴリズムを使って配列を並べ替えるPythonプログラムの実装方法を、初心者にもわかりやすく解説します。 問題の定義 問題: 与えられた配列を、クイックソートの考え方を利用して昇順にソートすることです。 クイックソートは「分割統治法」と呼ばれる手法に基づく高速なソートアルゴリズムです。まず配列を基準値(ピボット)を境目に2つの部分に分割し、それぞれの部分配列を再帰的にソートしていくことで、最終的に全体が整列された配列を得られます。 クイックソートの仕組み 処理の流れは以下のとおりです。 配列からピボット(基準となる要素)を選びます。こ