回答編集履歴
11
少し追記
answer
CHANGED
@@ -205,4 +205,10 @@
|
|
205
205
|
|
206
206
|
print(a.class_variable) # ここ
|
207
207
|
print(SharedMutableObject.class_variable) # ここ
|
208
|
-
```
|
208
|
+
```
|
209
|
+
|
210
|
+
特に、真ん中の`print(SharedMutableObject.class_variable)`の結果を実行せずに分かるなら、
|
211
|
+
|
212
|
+
> `{'state': 'second'}`がどこで保持され、二回目のインスタンス化である`test2 = TestBorg1()`の際に`{'state': 'second'}`を出力できるのでしょうか?
|
213
|
+
|
214
|
+
という疑問は解消されているはずです。(ここに書いたコードでは1回目は'first'を入れていますが)
|
10
些細
answer
CHANGED
@@ -186,7 +186,7 @@
|
|
186
186
|
|
187
187
|
(追記)
|
188
188
|
|
189
|
-
では以上を
|
189
|
+
では、以上の挙動をすべて理解できていれば、下の結果も実行せずにわかるはずです。
|
190
190
|
|
191
191
|
```python
|
192
192
|
class SharedMutableObject:
|
9
代入の変更
answer
CHANGED
@@ -194,7 +194,6 @@
|
|
194
194
|
|
195
195
|
a = SharedMutableObject()
|
196
196
|
a.instance_variable = a.class_variable # ポイントはこの代入文の意味
|
197
|
-
|
198
197
|
a.instance_variable["state"] = "first"
|
199
198
|
|
200
199
|
print(SharedMutableObject.class_variable) # ここ
|
@@ -202,9 +201,8 @@
|
|
202
201
|
|
203
202
|
b = SharedMutableObject()
|
204
203
|
b.instance_variable = b.class_variable
|
204
|
+
b.instance_variable["state"] = "second"
|
205
205
|
|
206
|
-
a.instance_variable["state"] = "second"
|
207
|
-
|
208
|
-
print(
|
206
|
+
print(a.class_variable) # ここ
|
209
207
|
print(SharedMutableObject.class_variable) # ここ
|
210
208
|
```
|
8
追記
answer
CHANGED
@@ -186,14 +186,14 @@
|
|
186
186
|
|
187
187
|
(追記)
|
188
188
|
|
189
|
-
ではこれの結果も実行せずにわかるはず。
|
189
|
+
では以上を合わせてこれの結果も実行せずにわかるはず。
|
190
190
|
|
191
191
|
```python
|
192
192
|
class SharedMutableObject:
|
193
193
|
class_variable = {}
|
194
194
|
|
195
195
|
a = SharedMutableObject()
|
196
|
-
a.instance_variable = a.class_variable
|
196
|
+
a.instance_variable = a.class_variable # ポイントはこの代入文の意味
|
197
197
|
|
198
198
|
a.instance_variable["state"] = "first"
|
199
199
|
|
7
追記
answer
CHANGED
@@ -180,4 +180,31 @@
|
|
180
180
|
|
181
181
|
print(b)
|
182
182
|
```
|
183
|
-
の結果は、実行せずにすぐ想像できるんでしょうか?
|
183
|
+
の結果は、実行せずにすぐ想像できるんでしょうか?
|
184
|
+
|
185
|
+
----
|
186
|
+
|
187
|
+
(追記)
|
188
|
+
|
189
|
+
ではこれの結果も実行せずにわかるはず。
|
190
|
+
|
191
|
+
```python
|
192
|
+
class SharedMutableObject:
|
193
|
+
class_variable = {}
|
194
|
+
|
195
|
+
a = SharedMutableObject()
|
196
|
+
a.instance_variable = a.class_variable
|
197
|
+
|
198
|
+
a.instance_variable["state"] = "first"
|
199
|
+
|
200
|
+
print(SharedMutableObject.class_variable) # ここ
|
201
|
+
|
202
|
+
|
203
|
+
b = SharedMutableObject()
|
204
|
+
b.instance_variable = b.class_variable
|
205
|
+
|
206
|
+
a.instance_variable["state"] = "second"
|
207
|
+
|
208
|
+
print(b.class_variable) # ここ
|
209
|
+
print(SharedMutableObject.class_variable) # ここ
|
210
|
+
```
|
6
些細
answer
CHANGED
@@ -174,7 +174,6 @@
|
|
174
174
|
|
175
175
|
```python
|
176
176
|
a = [1, 3, 2, 4]
|
177
|
-
|
178
177
|
b = a
|
179
178
|
|
180
179
|
a.sort()
|
5
追記
answer
CHANGED
@@ -154,4 +154,31 @@
|
|
154
154
|
|
155
155
|
print(a.x) # => aに属性xがあって10に束縛されているので10がプリントされる
|
156
156
|
print(b.x) # => bに属性xがないので、次にクラスの属性xを探す。1に束縛されているので1がプリントされる
|
157
|
-
```
|
157
|
+
```
|
158
|
+
|
159
|
+
----
|
160
|
+
(追記)
|
161
|
+
|
162
|
+
もう一段基本的なことを確認しておきたいんですが、
|
163
|
+
|
164
|
+
```python
|
165
|
+
a = {}
|
166
|
+
b = a
|
167
|
+
|
168
|
+
a['x'] = 1
|
169
|
+
|
170
|
+
print(b)
|
171
|
+
```
|
172
|
+
|
173
|
+
とか
|
174
|
+
|
175
|
+
```python
|
176
|
+
a = [1, 3, 2, 4]
|
177
|
+
|
178
|
+
b = a
|
179
|
+
|
180
|
+
a.sort()
|
181
|
+
|
182
|
+
print(b)
|
183
|
+
```
|
184
|
+
の結果は、実行せずにすぐ想像できるんでしょうか?
|
4
修正
answer
CHANGED
@@ -153,5 +153,5 @@
|
|
153
153
|
b = Bazz()
|
154
154
|
|
155
155
|
print(a.x) # => aに属性xがあって10に束縛されているので10がプリントされる
|
156
|
-
print(b.
|
156
|
+
print(b.x) # => bに属性xがないので、次にクラスの属性xを探す。1に束縛されているので1がプリントされる
|
157
157
|
```
|
3
追記
answer
CHANGED
@@ -51,4 +51,107 @@
|
|
51
51
|
|
52
52
|
----
|
53
53
|
|
54
|
-
`__dict__`を使った話が理解できるのは、まずこれらが分かってからかと思いますが大丈夫でしょうか。
|
54
|
+
`__dict__`を使った話が理解できるのは、まずこれらが分かってからかと思いますが大丈夫でしょうか。
|
55
|
+
|
56
|
+
|
57
|
+
----
|
58
|
+
(追記)
|
59
|
+
|
60
|
+
もう一段基本的な方からいきましょう。
|
61
|
+
|
62
|
+
Pythonでは、「自分で宣言したクラス」のインスタンスに対して、`インスタンス.属性 = 値`という代入文で**そのインスタンス**になにかの値に属性を束縛できます。
|
63
|
+
|
64
|
+
```python
|
65
|
+
class Foo:
|
66
|
+
pass
|
67
|
+
|
68
|
+
a = Foo()
|
69
|
+
a.x = 1
|
70
|
+
a.y = 2
|
71
|
+
|
72
|
+
b = Foo()
|
73
|
+
b.y = 3
|
74
|
+
|
75
|
+
print(a.x) # => 1がプリントされる
|
76
|
+
print(a.y) # => 2がプリントされる
|
77
|
+
print(b.x) # => 3がプリントされる
|
78
|
+
print(b.y) # => エラー
|
79
|
+
```
|
80
|
+
|
81
|
+
です。
|
82
|
+
`a.x`と`b.x`の値が異なることから、属性はインスタンス毎に付けることが分かります。
|
83
|
+
これがインスタンス変数です。
|
84
|
+
|
85
|
+
(脱線しますが、intやlistのようなPython言語のコアな組み込み型ではこの機構はありません。勝手に属性を追加されたりすると困るので)
|
86
|
+
|
87
|
+
クラス定義の外では、クラスに対して、`クラス.属性 = 値`という代入文で**そのクラス**になにかの値に属性を束縛できます。
|
88
|
+
|
89
|
+
```python
|
90
|
+
Foo.c = 1
|
91
|
+
|
92
|
+
print(Foo.c) # => 1がプリントされる
|
93
|
+
print(Foo.d) # => エラー
|
94
|
+
```
|
95
|
+
|
96
|
+
"クラス定義の外では"とわざわざ注釈を入れたのは、クラス定義の中では書けないからです。
|
97
|
+
|
98
|
+
```Python
|
99
|
+
class Bar:
|
100
|
+
Bar.c = 1 # => エラー
|
101
|
+
```
|
102
|
+
なぜかというと、Barという名前はclass文の**実行が終わった時**にできる名前だからです。
|
103
|
+
実行が終わってないところでは使えません。
|
104
|
+
|
105
|
+
どうするかというと
|
106
|
+
|
107
|
+
```Python
|
108
|
+
class Bar:
|
109
|
+
c = 1
|
110
|
+
|
111
|
+
print(Bar.c) # => 1
|
112
|
+
```
|
113
|
+
とします。
|
114
|
+
|
115
|
+
[https://docs.python.org/ja/3/tutorial/classes.html#class-objects](https://docs.python.org/ja/3/tutorial/classes.html#class-objects)
|
116
|
+
> クラスオブジェクトが生成された際にクラスの名前空間にあった名前すべてが有効な属性名です。
|
117
|
+
|
118
|
+
クラス宣言の実行部分で名前`c`が作られましたから、クラスBarは属性名cを持ちます
|
119
|
+
ということです。
|
120
|
+
|
121
|
+
```Python
|
122
|
+
class Bar:
|
123
|
+
c = 1
|
124
|
+
```
|
125
|
+
と
|
126
|
+
```python
|
127
|
+
class Bar:
|
128
|
+
pass
|
129
|
+
Bar.c = 1
|
130
|
+
```
|
131
|
+
は(実行される順番は違うけれども)結果が同じになります。
|
132
|
+
|
133
|
+
----
|
134
|
+
ここまで分かったら
|
135
|
+
|
136
|
+
[いろいろな注意点](https://docs.python.org/ja/3/tutorial/classes.html#random-remarks) に
|
137
|
+
> インスタンスとクラスの両方で同じ属性名が使用されている場合、属性検索はインスタンスが優先されます。
|
138
|
+
|
139
|
+
とありますが、
|
140
|
+
「インスタンスとクラスの両方で同じ属性を持っていればインスタンスが優先されます」という説明は、裏から言うと
|
141
|
+
`インスタンス.属性`という形でアクセスする時、インスタンスがその属性を持っていなければ**クラスの属性を見つけてくる**
|
142
|
+
|
143
|
+
と書いたのが分かるはずです。
|
144
|
+
|
145
|
+
|
146
|
+
```python
|
147
|
+
class Bazz:
|
148
|
+
x = 1
|
149
|
+
|
150
|
+
a = Bazz()
|
151
|
+
a.x = 10
|
152
|
+
|
153
|
+
b = Bazz()
|
154
|
+
|
155
|
+
print(a.x) # => aに属性xがあって10に束縛されているので10がプリントされる
|
156
|
+
print(b.z) # => bに属性xがないので、次にクラスの属性xを探す。1に束縛されているので1がプリントされる
|
157
|
+
```
|
2
追記
answer
CHANGED
@@ -31,6 +31,7 @@
|
|
31
31
|
b.test_shared() # => [1]がprintされて、Fuga.shared_listは[1, 1]になる
|
32
32
|
|
33
33
|
print(Fuga.shared_list) # Fuga.shared_listは[1, 1]なので[1, 1]がprintされる
|
34
|
+
print(b.shared_list) # shared_listがインスタンス属性から見つからないので、Fuga.shared_listが探索され、[1, 1]なので[1, 1]がprintされる
|
34
35
|
```
|
35
36
|
|
36
37
|
[クラスとインスタンス変数](https://docs.python.org/ja/3/tutorial/classes.html#class-and-instance-variables) の
|
1
リンク追加
answer
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
まず(`__dict__`は完全に忘れて)普通のクラス変数の取り扱いは分かるでしょうか。
|
1
|
+
まず(`__dict__`は完全に忘れて)普通の[クラス変数](https://docs.python.org/ja/3/tutorial/classes.html#class-objects)の取り扱いは分かるでしょうか。
|
2
2
|
```python
|
3
3
|
class Hoge:
|
4
4
|
shared_list = []
|
@@ -33,8 +33,7 @@
|
|
33
33
|
print(Fuga.shared_list) # Fuga.shared_listは[1, 1]なので[1, 1]がprintされる
|
34
34
|
```
|
35
35
|
|
36
|
-
[クラスとインスタンス変数](https://docs.python.org/ja/3/tutorial/classes.html#class-and-instance-variables)
|
36
|
+
[クラスとインスタンス変数](https://docs.python.org/ja/3/tutorial/classes.html#class-and-instance-variables) の
|
37
|
-
の
|
38
37
|
> 名前とオブジェクトについて で議論したように、共有データはリストや辞書のような mutable オブジェクトが関与すると驚くべき効果を持ち得ます。
|
39
38
|
|
40
39
|
|
@@ -42,8 +41,7 @@
|
|
42
41
|
|
43
42
|
|
44
43
|
|
45
|
-
[いろいろな注意点](https://docs.python.org/ja/3/tutorial/classes.html#random-remarks)
|
44
|
+
[いろいろな注意点](https://docs.python.org/ja/3/tutorial/classes.html#random-remarks) に
|
46
|
-
|
47
45
|
> インスタンスとクラスの両方で同じ属性名が使用されている場合、属性検索はインスタンスが優先されます。
|
48
46
|
|
49
47
|
とありますが、
|