ProgrammingPython開発者

Pythonにおける保護された変数とメソッドおよびプライベート変数とメソッドとは何であり、カプセル化はどのように実現され、Pythonは実際にオブジェクトの内部状態をどれほど保護しているのか?

Hintsage AIアシスタントで面接を突破

回答。

問題の歴史
クラシックなオブジェクト指向プログラミングにおいて、カプセル化は内部データへのアクセス制限を通じて実現されます。ほとんどの言語には厳密なアクセス修飾子がありますが、Pythonには「みんな大人だから」という原則があり、厳密なプライバシーは存在しません。

問題
開発者はPythonにおける保護された(_protected)およびプライベート(__private)属性とメソッドを混同し、「ダブルアンダースコア」が完全な保護を提供すると考えたり、全く保護がないと考えたりしています。

解決策
Pythonは協約を実装しています:シングルアンダースコア _var は保護されたものであり、ダブルアンダースコア __var はプライベート(名前マングリングが行われる)です。そのため、こうした属性やメソッドへのアクセスは可能ですが、難しくなります:_ClassName__varとして呼び出されます。

コードの例:

class Example: def __init__(self): self._protected = 1 # 保護された self.__private = 2 # プライベート(名前マングリング) ex = Example() print(ex._protected) # 1 #print(ex.__private) # AttributeError print(ex._Example__private) # 2(名前マングリング)

主な特徴:

  • シングルアンダースコアは協約であり、「クラスおよび階層の外では触れない」ことを意味します。
  • ダブルアンダースコアは名前マングリングであり、バイトコード内で変数名にクラス名が追加されます。
  • Pythonはアクセスを禁止するのではなく、アクセスを難しくします。これは協約であり、厳格な制限ではありません。

トリックのある質問。

インスタンスを通じて「プライベート」フィールドにアクセスすることはできますか?

はい、マングリングを通じて:_ClassName__varです。したがって、データは利用可能ですが、暗黙的です。

継承時にプライベートメソッド/属性はどうなりますか?

名前マングリングは、子クラスが親のプライベート要素を偶発的にオーバーライドすることを防ぎますが、_ParentClass__attrを介してアクセスすることはできます。ダブルアンダースコアのメソッドは、子クラスからは「見えません」。

class A: def __foo(self): print("A") class B(A): def bar(self): # self.__foo() — エラー self._A__foo() # 動作する

PythonにはJVM/C++レベルの完全なプライバシーがありますか?

いいえ。すべては協約とマングリングに基づいています。データを完全に保護することはできません。Pythonは動的に任意の属性へのアクセスを許可します。

一般的な間違いとアンチパターン

  • ダブルアンダースコアによる完全な保護を期待すること。
  • 継承者でプライベートメソッドを使用し、可読性や拡張性を損なうこと。
  • シングルアンダースコアで十分な場合にダブルアンダースコアを大量に使用すること。

実生活の例

ネガティブケース

大きなライブラリでユーザーがダブルアンダースコアを使ってプライベート属性を変更しようとしたが、これは「秘密」だと思っていましたが、_ClassName__varを介して変更は引き続き発生しました。

利点:

  • オートコンプリートから属性を形式的に隠すこと。

欠点:

  • プライバシーに対する偽の幻想。
  • クラスの不変条件を壊す可能性。

ポジティブケース

プロジェクト内で内部フィールドにはシングルアンダースコアを使用し、クラスの外からは触れないことに合意しました。安全なアクセスのためにプロパティを追加しました。

利点:

  • 可読性と協約の遵守。
  • コードの保守が容易。

欠点:

  • 厳密なプライバシーの欠如:不注意な開発者が協約を破ってアクセスする可能性。