質問するログイン新規登録

回答編集履歴

3

追記

2020/04/01 06:28

投稿

hayataka2049
hayataka2049

スコア30941

answer CHANGED
@@ -26,7 +26,7 @@
26
26
 
27
27
  厳密に言えば、振る舞いは同一ではありません。
28
28
 
29
- とりあえず、以下のように書き直すことにします。
29
+ とりあえず、わかりやすくするために以下のように書き直すことにします。
30
30
 
31
31
  ```python
32
32
  def calc(self):
@@ -34,14 +34,16 @@
34
34
  self.val_b = self.val_b + 1
35
35
  ```
36
36
 
37
- の`self.val_a`, `self.val_b`「何」にアクセスしているかが問題です。
37
+ 結論を先に行ってしまうと、左辺で代入している対象はどちらもインスタンス変数(インスタンスの属性)です。
38
38
 
39
+ ただし、右辺の`self.val_a`, `self.val_b`で「何」にアクセスしているかが問題です。
40
+
39
41
  - `self`の属性からはクラス変数にもインスタンス変数にもアクセスできる
40
42
  - 同名で両方あるときはインスタンス変数の方が優先順位が高い
41
43
 
42
- という規則があり、Aの方ではインスタンス変数、Bの方ではクラス変数へのアクセスになります。
44
+ という規則があり、そのためAの方ではインスタンス変数、Bの方ではクラス変数へのアクセスになります。
43
45
 
44
- そしてPythonでは属性への代入で新たな属性(ここではインスタンス変数)を作ることができますから、`A`の方はもともとあったインスタンス変数を書き換えるだけですが、`B`では`calc`が呼び出された瞬間に新規にクラス変数と同名のインスタンス変数を作っていることになります。
46
+ そしてPythonでは属性への代入で新たな属性(ここではインスタンス変数)を作ることができます。よって、`A`の方はもともとあったインスタンス変数を書き換えるですが、`B`では`calc`が呼び出された瞬間に新規にクラス変数と同名のインスタンス変数を作っていることになります。
45
47
 
46
48
  ---
47
49
 
@@ -80,4 +82,14 @@
80
82
  print(h2.lst) # [1, 1]
81
83
 
82
84
 
83
- ```
85
+ ```
86
+
87
+ わざわざクラス変数と同名のインスタンス変数に代入を行わなければ、基本的にはクラス変数が見える状態のままであることに注意してください。
88
+
89
+ 細かい解説は不要かと思いますが、クラス変数は全インスタンスで共有されますので、最後の行のような結果になります。
90
+
91
+ ---
92
+
93
+ `self`からクラス変数へアクセスするのは、比較的挙動がわかりづらく、混乱を招きがちなのであまり推奨されていない気がします。
94
+
95
+ 明示的にクラス変数へアクセスしたい場合は、`type(self).val_a`などがいいでしょう。

2

追記

2020/04/01 06:28

投稿

hayataka2049
hayataka2049

スコア30941

answer CHANGED
@@ -41,4 +41,43 @@
41
41
 
42
42
  という規則があり、Aの方ではインスタンス変数、Bの方ではクラス変数へのアクセスになります。
43
43
 
44
- そしてPythonでは属性への代入で新たな属性(ここではインスタンス変数)を作ることができますから、`A`の方はもともとあったインスタンス変数を書き換えるだけですが、`B`では`calc`が呼び出された瞬間に新規にクラス変数と同名のインスタンス変数を作っていることになります。
44
+ そしてPythonでは属性への代入で新たな属性(ここではインスタンス変数)を作ることができますから、`A`の方はもともとあったインスタンス変数を書き換えるだけですが、`B`では`calc`が呼び出された瞬間に新規にクラス変数と同名のインスタンス変数を作っていることになります。
45
+
46
+ ---
47
+
48
+ といってもまあ結果論としては同じように見えてしまう例ですね。
49
+
50
+ immutableなオブジェクトを束縛した変数の挙動、累積代入文、クラス変数とインスタンス変数の優先順位、属性への代入など、Pythonのわかりづらいところが複数重なっているとても厄介な例です。もう少し単純なものを見ておきましょう。mutableの`list`にして要素を追加してみます。
51
+
52
+ ```python
53
+ class hoge_A:
54
+ def __init__(self):
55
+ self.lst = []
56
+
57
+ def append1(self):
58
+ self.lst.append(1)
59
+
60
+ class hoge_B:
61
+ lst = []
62
+ def append1(self):
63
+ self.lst.append(1)
64
+
65
+ h1 = hoge_A()
66
+ h1.append1()
67
+ print(h1.lst) # [1]
68
+
69
+ h2 = hoge_A()
70
+ h2.append1()
71
+ print(h2.lst) # [1]
72
+
73
+
74
+ h1 = hoge_B()
75
+ h1.append1()
76
+ print(h1.lst) # [1]
77
+
78
+ h2 = hoge_B()
79
+ h2.append1()
80
+ print(h2.lst) # [1, 1]
81
+
82
+
83
+ ```

1

修正

2020/03/31 15:39

投稿

hayataka2049
hayataka2049

スコア30941

answer CHANGED
@@ -18,7 +18,7 @@
18
18
  Hoge.a = 10
19
19
  ```
20
20
 
21
- もっと端的にいえば、Aは「インスタンス変」、Bは「クラス変数」という言葉でそれぞれ呼ばれます。
21
+ もっと端的にいえば、Aは「インスタンス変」、Bは「クラス変数」という言葉でそれぞれ呼ばれます。
22
22
 
23
23
  ---
24
24