回答編集履歴

3

追記

2020/04/01 06:28

投稿

hayataka2049
hayataka2049

スコア30935

test CHANGED
@@ -54,7 +54,7 @@
54
54
 
55
55
 
56
56
 
57
- とりあえず、以下のように書き直すことにします。
57
+ とりあえず、わかりやすくするために以下のように書き直すことにします。
58
58
 
59
59
 
60
60
 
@@ -70,7 +70,11 @@
70
70
 
71
71
 
72
72
 
73
+ 結論を先に行ってしまうと、左辺で代入している対象はどちらもインスタンス変数(インスタンスの属性)です。
74
+
75
+
76
+
73
- 右辺の`self.val_a`, `self.val_b`で「何」にアクセスしているかが問題です。
77
+ ただし、右辺の`self.val_a`, `self.val_b`で「何」にアクセスしているかが問題です。
74
78
 
75
79
 
76
80
 
@@ -80,11 +84,11 @@
80
84
 
81
85
 
82
86
 
83
- という規則があり、Aの方ではインスタンス変数、Bの方ではクラス変数へのアクセスになります。
87
+ という規則があり、そのためAの方ではインスタンス変数、Bの方ではクラス変数へのアクセスになります。
84
88
 
85
89
 
86
90
 
87
- そしてPythonでは属性への代入で新たな属性(ここではインスタンス変数)を作ることができますから、`A`の方はもともとあったインスタンス変数を書き換えるだけですが、`B`では`calc`が呼び出された瞬間に新規にクラス変数と同名のインスタンス変数を作っていることになります。
91
+ そしてPythonでは属性への代入で新たな属性(ここではインスタンス変数)を作ることができます。よって、`A`の方はもともとあったインスタンス変数を書き換えるですが、`B`では`calc`が呼び出された瞬間に新規にクラス変数と同名のインスタンス変数を作っていることになります。
88
92
 
89
93
 
90
94
 
@@ -163,3 +167,23 @@
163
167
 
164
168
 
165
169
  ```
170
+
171
+
172
+
173
+ わざわざクラス変数と同名のインスタンス変数に代入を行わなければ、基本的にはクラス変数が見える状態のままであることに注意してください。
174
+
175
+
176
+
177
+ 細かい解説は不要かと思いますが、クラス変数は全インスタンスで共有されますので、最後の行のような結果になります。
178
+
179
+
180
+
181
+ ---
182
+
183
+
184
+
185
+ `self`からクラス変数へアクセスするのは、比較的挙動がわかりづらく、混乱を招きがちなのであまり推奨されていない気がします。
186
+
187
+
188
+
189
+ 明示的にクラス変数へアクセスしたい場合は、`type(self).val_a`などがいいでしょう。

2

追記

2020/04/01 06:28

投稿

hayataka2049
hayataka2049

スコア30935

test CHANGED
@@ -85,3 +85,81 @@
85
85
 
86
86
 
87
87
  そしてPythonでは属性への代入で新たな属性(ここではインスタンス変数)を作ることができますから、`A`の方はもともとあったインスタンス変数を書き換えるだけですが、`B`では`calc`が呼び出された瞬間に新規にクラス変数と同名のインスタンス変数を作っていることになります。
88
+
89
+
90
+
91
+ ---
92
+
93
+
94
+
95
+ といってもまあ結果論としては同じように見えてしまう例ですね。
96
+
97
+
98
+
99
+ immutableなオブジェクトを束縛した変数の挙動、累積代入文、クラス変数とインスタンス変数の優先順位、属性への代入など、Pythonのわかりづらいところが複数重なっているとても厄介な例です。もう少し単純なものを見ておきましょう。mutableの`list`にして要素を追加してみます。
100
+
101
+
102
+
103
+ ```python
104
+
105
+ class hoge_A:
106
+
107
+ def __init__(self):
108
+
109
+ self.lst = []
110
+
111
+
112
+
113
+ def append1(self):
114
+
115
+ self.lst.append(1)
116
+
117
+
118
+
119
+ class hoge_B:
120
+
121
+ lst = []
122
+
123
+ def append1(self):
124
+
125
+ self.lst.append(1)
126
+
127
+
128
+
129
+ h1 = hoge_A()
130
+
131
+ h1.append1()
132
+
133
+ print(h1.lst) # [1]
134
+
135
+
136
+
137
+ h2 = hoge_A()
138
+
139
+ h2.append1()
140
+
141
+ print(h2.lst) # [1]
142
+
143
+
144
+
145
+
146
+
147
+ h1 = hoge_B()
148
+
149
+ h1.append1()
150
+
151
+ print(h1.lst) # [1]
152
+
153
+
154
+
155
+ h2 = hoge_B()
156
+
157
+ h2.append1()
158
+
159
+ print(h2.lst) # [1, 1]
160
+
161
+
162
+
163
+
164
+
165
+ ```

1

修正

2020/03/31 15:39

投稿

hayataka2049
hayataka2049

スコア30935

test CHANGED
@@ -38,7 +38,7 @@
38
38
 
39
39
 
40
40
 
41
- もっと端的にいえば、Aは「インスタンス変」、Bは「クラス変数」という言葉でそれぞれ呼ばれます。
41
+ もっと端的にいえば、Aは「インスタンス変」、Bは「クラス変数」という言葉でそれぞれ呼ばれます。
42
42
 
43
43
 
44
44