[Pythonクイズ]あるはずの属性にアクセスできない? そんなことってあるの?Pythonステップアップクイズ

クラスには属性が付きものです。その属性にアクセスしたくてもうまくいかないときがあるんですよね。そんなことを今回は問題にしました(あ、これヒントになってるじゃん!)。

» 2025年11月04日 05時00分 公開
[かわさきしんじDeep Insider編集部]
「Pythonステップアップクイズ」のインデックス

連載目次

MyClassのオブジェクトを作成し、そのメンバーにアクセスするコード。実行するとどうなるかな? MyClassのオブジェクトを作成し、そのメンバーにアクセスするコード。実行するとどうなるかな?

【問題】

 以下のコードではMyClassクラスを定義して、そのオブジェクトを作成し、その属性にアクセスしている。このコードを実行するとどうなるだろう。

class MyClass:
    def __init__(self, a=1, b=2, c=3):
        self.a = a
        self._b = b
        self.__c = c


c = MyClass()
print(c.a)
print(c._b)
print(c.__c)

MyClassのオブジェクトを作成し、そのメンバーにアクセスするコード。実行するとどうなるかな?

Pythonの哲学?

 このクイズに関連して、ChatGPT(GPT-5)/Gemini(Gemini 2.5 Flash)/Calude(Claude Opus 4.1)の3つの大規模言語モデル(LLM)にあることを聞いてみました。何を聞いたかを書くと大きなヒントになっちゃうかもしれません。が、まあいいですかね。「Pythonにもプライベートな属性にアクセスできなくするような強制的な仕組みが必要だとは思いませんか?」と聞いたんです。

 そしたら、3つのLLMがみんな同じ言葉を基にした答えを返してくれました。さて、そのお言葉とは何だったのでしょう。



かわさき

 どうもHPかわさきです。

 今回はクラスについてちゃんと勉強していれば、そんなに難しい問題ではないような気もします。クイズの問題の難易度って、どうすればうまく設定できるんでしょうかねぇ。いっつも困っています。どうやって問題をひねり出しているかというと、いろいろなWebページや書籍を見ながら、あるいはコードを書きながら「これはクイズにできるかも?」というところがスタート地点になるので、どうしても易しい/難しいよりも取り扱うネタが優先されちゃうのです。そういうわけで、サクッと答えてみてくださいね!


【答え】

 正解は「c.__c属性にアクセスしようとするとAttributeError例外が発生する」でした。

c.__c属性にはアクセスできない! c.__c属性にはアクセスできない!

 以下ではその理由を説明します。

【解説】

 問題文のコードは次のようなものでした。

class MyClass:
    def __init__(self, a=1, b=2, c=3):
        self.a = a
        self._b = b
        self.__c = c


c = MyClass()
print(c.a)
print(c._b)
print(c.__c)

MyClassのオブジェクトを作成し、そのメンバーにアクセスするコード

 MyClassクラスには「a」「_b」「__c」という3つの属性があります。ここで一つ、注意してください。それは、Pythonのドキュメント「9. クラス」の「9.6 プライベート変数」には「アンダースコアで始まる名前(例えば_spam)は、(関数であれメソッドであれデータメンバであれ)非publicなAPIとして扱います」とあることです。


かわさき

 引用文では「プライベート変数」「メソッド」「メンバ」などの言葉が使われていますが、ざっくりといえば、これらはPythonのクラス(もしくはそのインスタンス)が持つ属性のことだと考えられます。よって、以下ではこだわらずに「属性」という語を使います。


 「非publicなAPI」というのは、クラスの内部でのみ使用することを意図したものであるという意味であり、そのクラスを使う側が「触るべきではない」ことがコードとして示されているということです。Python以外の言語の多くでは、そうした属性やメンバー、メソッドには外部から自由にアクセスできないような機構がありますが、Pythonにはそうしたものはありません。

 つまり、クラスを定義した側のプログラマーが「これはプライベートな属性」としたところで、使用する側がプライベートな属性へアクセスすることを妨げることができません。その代わりに、プログラマーはアンダースコアで始まる名前を使って「これはプライベートだから触らないようにしてね」とコード中に記述し、それを使う側はアンダースコアで始まる名前の属性については「これはプライベートなものだから(極力)触らない」ようにするのです。

 このような「紳士協定」を守ることで、Pythonではプライベートな属性の保護がなされています(上でも述べたように、プライベートな属性を保護する機構はないので、それに触らないようにするのはあくまでも「紳士協定」なのです)。さらに2つのアンダースコアで始まり、最後に0個または1個のアンダースコアが付く名前については「マングリング」と呼ばれる処理が行われます。

 例えば、問題文のコードにあった「__c」という属性はマングリングにより、「_MyClass__c」という名前に置き換えられます(クラス内で定義されたメソッドでは「__c」でアクセスできますが、これはメソッド内に登場する「__c」もまた「_MyClass__c」に置き換えられているからです)。

 バイトコードのレベルで、上記のクラスがどうなっているかを見てみましょう。

dis.dis関数でMyClassのバイトコードを表示したところ dis.dis関数でMyClassのバイトコードを表示したところ

 a属性と_b属性はバイトコードの中にも登場しますが、__c属性はバイトコードのレベルで「_MyClass__c」になっていることが分かります。

 さらにc属性の値をprint関数で出力するメソッドを以下のように定義してみましょう。

class MyClass:
    def __init__(self, a=1, b=2, c=3):
        self.a = a
        self._b = b
        self.__c = c

    def print__c(self):
        print(self.__c) 

メソッド内で__c属性にアクセスする

 このMyClassクラスのバイトコードは次のようになります。

メソッド内での「self.__c」というアクセスもバイトコードでは「_MyClass__c」に置き換えられている メソッド内での「self.__c」というアクセスもバイトコードでは「_MyClass__c」に置き換えられている

 print__cメソッドでは「self.__c」としてオブジェクトの__c属性にアクセスしていますが、バイトコードを見るとやはり「_MyClass__c」という名前が使われているのが分かります。

 こうしたことから、外部から「c.__c」のようにアクセスしようとしても、「そんな属性はない」とAttributeError例外が発生してしまうのです。ではどうしてもこの属性にアクセスしたいというときにはどうしたらよいかというと、マングリング後の名前を使います。

class MyClass:
    def __init__(self, a=1, b=2, c=3):
        self.a = a
        self._b = b
        self.__c = c


c = MyClass()
print(c.a)  # 1
print(c._b)  # 2
print(c._MyClass__c)  # 3

マングリング後の名前を使えばアクセスは可能

 アクセスは可能ですが、そうしたことをすべきではない、ことは心に留めてそうするようにしましょう。プライベートな属性はクラス内部で使われることを意図しています。クラスを書き替えていく中で、そうした属性がなくなったり、名前が変わったり、それがメソッドであれば動作が変わったりする可能性があります。そのような目に遭った際に開発者に文句はいえません。


かわさき

 さて3つのLLMの答えに共通したのは、Pythonの哲学とされる「We're all consenting adults here」というフレーズでした。日本語にすると「ここにいるのは全員、分別のある大人でしょ」といった感じでしょうか? つまり、プライベートな属性へのアクセス制限を設けずに、「プライベートな属性はアンダースコアで始まる名前を付けることで、そうであると示す」「クラスを使う側を信頼する」「プライベートな属性にアクセスするときにはリスクがあることを理解する」といった考え方をPythonプログラマーは理解して受け入れているよねというお話です。

 あ、「Pythonにもプライベートな属性にアクセスできなくするような強制的な仕組みが必要だとは思いませんか?」という問いについては、以下のような結論になっていました。

  • ChatGPT:Pythonに強制的なプライベートがないのは、欠陥ではなく設計思想が違うから
  • Gemini:Pythonに強制的なプライベート属性の仕組みは、その設計哲学に反するため不要
  • Claude:プロジェクトの性質による

 要するに3つのLLMとも、「Pythonが強制的なprivateを持たないのは意図的な設計であり、柔軟性と信頼の文化の表れである」と答えてくれた、というわけですね。この他にも、Pythonが持つ柔軟性を損なうことにもつながりかねないという話も出ていました。皆さんはどう思いますか? 僕は今のままでいいかなぁ(特に何も考えていない)。


「Pythonステップアップクイズ」のインデックス

Pythonステップアップクイズ

Copyright© Digital Advantage Corp. All Rights Reserved.

アイティメディアからのお知らせ

スポンサーからのお知らせPR

注目のテーマ

4AI by @IT - AIを作り、動かし、守り、生かす
Microsoft & Windows最前線2025
AI for エンジニアリング
ローコード/ノーコード セントラル by @IT - ITエンジニアがビジネスの中心で活躍する組織へ
Cloud Native Central by @IT - スケーラブルな能力を組織に
システム開発ノウハウ 【発注ナビ】PR
あなたにおすすめの記事PR

RSSについて

アイティメディアIDについて

メールマガジン登録

@ITのメールマガジンは、 もちろん、すべて無料です。ぜひメールマガジンをご購読ください。