質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.50%
Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

Q&A

5回答

733閲覧

プライベート変数について教えてほしい

test141

総合スコア10

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

1グッド

0クリップ

投稿2019/05/14 05:08

プライベート変数は外部からアクセスできないと認識しております。
確かに、ob.__num = 321 で値を代入し、ob.print()で確認すると、値は変更できていない
ことを確認しましたが、print(ob.__num)では値が変更されている、つまりアクセスできいるのですが
どういうことでしょうか。

class MyObj: def __init__(self): self.__num = 123 def print(self): print(self.__num) ob = MyObj() ob.__num = 321 ob.print() print(ob.__num)
nouken👍を押しています

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

quickquip

2019/05/14 05:17 編集

123 321 と意図した結果になりませんか?
test141

2019/05/14 05:20

print(ob.__num) を実行すると 123 になると思いました。 プライベート変数なので、 ob.__num = 321 を実行してもアクセスできない変更できない認識でいます。
quickquip

2019/05/14 05:25

マングリングが起きるのは**いつなのか**という質問だと理解しましたが、すでに回答がついているようなので。
guest

回答5

0

プライベート変数

~~
そういう言葉はありません。少なくともpythonの世界では。
~~

検索 — Python 3.7.3 ドキュメント

~~ドキュメントにはプライベートな名前と書いてあるみたいですね。
~~

チュートリアルではプライベート変数という言葉も使っているようです。

とりあえず厳密な意味での(絶対に外部から参照できない)「プライベート変数」はpythonにはない、そういう名前で呼ぶことも(原則的には)ない、としておきます。


アンダーバー2つの属性はマングリングによって処理されます。

プライベートな名前のマングリング: クラス定義内に書かれた識別子で、2つ以上のアンダースコアから始まり、末尾が2つ以上のアンダースコアで終わっていないものは、そのクラスの プライベートな名前 とみなされます。プライベートな名前は、コードが生成される前により長い形式に変換されます。この変換によって、クラス名の先頭にアンダースコアがあれば除去し、先頭にアンダースコアを1つ付加し、名前の前に挿入されます。例えば、クラス名 Ham の中の識別子 __spam は、_Ham__spam に変換されます。変換は識別子が使用されている構文のコンテキストからは独立しています。変換された名前が非常に長い (255文字を超える) 場合、実装によっては名前の切り詰めが行われるかもしれません。クラス名がアンダースコアのみから成る場合は変換は行われません。

6. 式 (expression) — Python 3.7.3 ドキュメント

__num_MyObj__numに変換されるので、外部から参照できない「ように見える」だけです。書き換える場合はこちらに対して代入する必要があります。

python

1ob = MyObj() 2ob._MyObj__num = 321 3ob.print() # 321

ではob.__numに対して代入すると? というと、前提としてpythonのオブジェクトは代入によって新しい属性を作ることができます。

python

1>>> class A: 2... pass 3... 4>>> a = A() 5>>> a.hoge 6Traceback (most recent call last): 7 File "<stdin>", line 1, in <module> 8AttributeError: 'A' object has no attribute 'hoge' 9>>> a.hoge = 42 10>>> a.hoge 1142 12

ob.__num = 321という文はクラス定義の外にあるので、マングリングは働かずそのまま__numという属性が新たに作られます。

投稿2019/05/14 05:21

編集2019/05/14 05:52
hayataka2049

総合スコア30933

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

退会済みユーザー

退会済みユーザー

2019/05/14 05:47 編集

> チュートリアルではプライベート変数という言葉も使っているようです。 記述にあるんだ。。。気持ち悪いなぁ^^;
guest

0

一応補足として。

  • マングリングが実施されるのはclass文を実行した時です。
  • マングリングの対象になるのは変数ではありません。クラス定義内にある識別子です。

python

1class Hoge: 2 def __init__(__self): 3 __hoge = 1 4 print(locals())

と書いてHoge()を実行すると

{'_Hoge__hoge': 1, '_Hoge__self': <__main__.Hoge object at 0x10c009390>}

となるのが確認できます。
クラス変数なのかローカル変数なのか引数なのかメソッド名なのかというような、「その識別子がなんであるか?」という区別なしに、マングリング対象になる識別子はすべて書き換えられているわけです。

上のソースは

python

1class Hoge: 2 def __init__(_Hoge__self): 3 _Hoge__hoge = 1 4 print(locals())

とかわりありません。


難号化の規則は主に不慮の事故を防ぐためのものだということに注意してください

とチュートリアルにある通り、この機能は名前をプライベートにするためのものではありません。

投稿2019/05/14 05:44

quickquip

総合スコア11029

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

Pythonの名前の衝突を避ける仕様が働いています。

Python

1print(ob.__num) # -> 321と出力 2print(ob._MyObj__num) # -> 123 と出力

9.6. プライベート変数

クラスのプライベートメンバについて適切なユースケース(特にサブクラスで定義された名前との衝突を避ける場合)があるので、マングリング(name mangling) と呼ばれる、限定されたサポート機構があります。 __spam (先頭に二個以上の下線文字、末尾に一個以下の下線文字) という形式の識別子は、 _classname__spam へとテキスト置換されるようになりました。ここで classname は、現在のクラス名から先頭の下線文字をはぎとった名前になります。このような難号化 (mangle) は、識別子の文法的な位置にかかわらず行われるので、クラス定義内に現れた識別子全てに対して実行されます。

投稿2019/05/14 05:20

編集2019/05/14 05:21
mar-kn

総合スコア306

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

hayataka2049

2019/05/14 05:26

あれ、プライベート変数ってチュートリアルで出てくるんですね。なんで検索で引っかからなかったんだろう。
mar-kn

2019/05/14 05:39

出てきはするのですが、説明の冒頭に >オブジェクトの中からしかアクセス出来ない 「プライベート」 インスタンス変数は、 Python にはありません。 とあるので、実際は無いよ!と言いながらも、多言語から入ってくる人たちが分かりやすいように「プライベート変数」と銘打っているのだと思います。 検索は「プライベート」だと引っかかるのですが、「プライベート変数」ではかからないですね…。 検索インデックスの作られ方が微妙です。
退会済みユーザー

退会済みユーザー

2019/05/14 05:48

記述にあるのかと思ったら、微妙な表現なんですね。理解できました。
guest

0

Pythonのプライベート変数は変数名への変更になっているためです。

python

1class A: 2 def __init__(self): 3 self.__private = 1 4 def print(self): 5 print(self.__private) 6a = A() 7a.__private = 2 8a.print() 9print(a.__private) 10 11print(vars(a))
1 2 {'_A__private': 1, '__private': 2}

投稿2019/05/14 05:21

mkgrei

総合スコア8560

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

アンダースコアが二つ付いた変数識別子はマングリングされます。
ただし外部から新たに属性を加える場合はそのままです。

Python

1>>> class MyClass: 2... def __init__(self): 3... self.__attr = 1 4... 5>>> inst = MyClass() 6>>> inst.__attr = 2 7>>> 8>>> dir(inst) 9['_MyClass__attr', '__attr', '__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__'] 10>>> 11>>> inst._MyClass__attr 121 13>>> inst.__attr 142

別のオブジェクトとして扱われているのが分かります。

コメントを受けて

この両者(self.__attrinst.__attr)は違うのでしょうか

hayataka2049さんが引用されている文章の中に、次のような記述があります。

クラス定義内に書かれた識別子で ...後略

単にどこに書かれているかが問題なわけです。
次のコードでもそれを確認することができます。

Python

1class MyClassA: 2 def __init__(self, inst): 3 inst.__attr = 42 4 5 6class MyClassB: 7 def __init__(self): 8 pass 9 10 11b = MyClassB() 12a = MyClassA(b) 13 14print(vars(b))

実行結果 Wandbox

{'_MyClassA__attr': 42}

MyClassBの属性なのに、MyClassAの名前を冠されているのはなかなか面白い挙動ですね。

投稿2019/05/14 05:24

編集2019/05/14 06:52
LouiS0616

総合スコア35658

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

test141

2019/05/14 05:52

ご回答ありがとうございます。 クラスを定義しているブロックに下記を追記します。 >>> class MyClass: ... def __init__(self): ... self.__attr = 1 ...   def print(self):    print(self.__attr) >>> inst = MyClass() >>> inst.__attr = 2 この場合、inst.print()を実行すると、1 が返って来ますよね。 でも、print(inst.__attr)を実行すると、2 が返ってきます。 この両者(self.__attr と inst.__attr)は違うのでしょうか
hayataka2049

2019/05/14 08:20

print(self.__attr) も同様に print(self._MyClass__attr) に変換された結果と捉えるのが一番いいんじゃないでしょうか。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.50%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問