回答編集履歴

11

少し追記

2021/05/19 03:57

投稿

quickquip
quickquip

スコア11038

test CHANGED
@@ -413,3 +413,15 @@
413
413
  print(SharedMutableObject.class_variable) # ここ
414
414
 
415
415
  ```
416
+
417
+
418
+
419
+ 特に、真ん中の`print(SharedMutableObject.class_variable)`の結果を実行せずに分かるなら、
420
+
421
+
422
+
423
+ > `{'state': 'second'}`がどこで保持され、二回目のインスタンス化である`test2 = TestBorg1()`の際に`{'state': 'second'}`を出力できるのでしょうか?
424
+
425
+
426
+
427
+ という疑問は解消されているはずです。(ここに書いたコードでは1回目は'first'を入れていますが)

10

些細

2021/05/19 03:57

投稿

quickquip
quickquip

スコア11038

test CHANGED
@@ -374,7 +374,7 @@
374
374
 
375
375
 
376
376
 
377
- では以上を合わせれの結果も実行せずにわかるはず。
377
+ では以上の挙動すべ理解できていば、下の結果も実行せずにわかるはずです
378
378
 
379
379
 
380
380
 

9

代入の変更

2021/05/19 03:45

投稿

quickquip
quickquip

スコア11038

test CHANGED
@@ -390,8 +390,6 @@
390
390
 
391
391
  a.instance_variable = a.class_variable # ポイントはこの代入文の意味
392
392
 
393
-
394
-
395
393
  a.instance_variable["state"] = "first"
396
394
 
397
395
 
@@ -406,13 +404,11 @@
406
404
 
407
405
  b.instance_variable = b.class_variable
408
406
 
409
-
410
-
411
- a.instance_variable["state"] = "second"
407
+ b.instance_variable["state"] = "second"
412
-
413
-
414
-
408
+
409
+
410
+
415
- print(b.class_variable) # ここ
411
+ print(a.class_variable) # ここ
416
412
 
417
413
  print(SharedMutableObject.class_variable) # ここ
418
414
 

8

追記

2021/05/16 23:50

投稿

quickquip
quickquip

スコア11038

test CHANGED
@@ -374,7 +374,7 @@
374
374
 
375
375
 
376
376
 
377
- ではこれの結果も実行せずにわかるはず。
377
+ では以上を合わせてこれの結果も実行せずにわかるはず。
378
378
 
379
379
 
380
380
 
@@ -388,7 +388,7 @@
388
388
 
389
389
  a = SharedMutableObject()
390
390
 
391
- a.instance_variable = a.class_variable
391
+ a.instance_variable = a.class_variable # ポイントはこの代入文の意味
392
392
 
393
393
 
394
394
 

7

追記

2021/05/16 23:47

投稿

quickquip
quickquip

スコア11038

test CHANGED
@@ -363,3 +363,57 @@
363
363
  ```
364
364
 
365
365
  の結果は、実行せずにすぐ想像できるんでしょうか?
366
+
367
+
368
+
369
+ ----
370
+
371
+
372
+
373
+ (追記)
374
+
375
+
376
+
377
+ ではこれの結果も実行せずにわかるはず。
378
+
379
+
380
+
381
+ ```python
382
+
383
+ class SharedMutableObject:
384
+
385
+ class_variable = {}
386
+
387
+
388
+
389
+ a = SharedMutableObject()
390
+
391
+ a.instance_variable = a.class_variable
392
+
393
+
394
+
395
+ a.instance_variable["state"] = "first"
396
+
397
+
398
+
399
+ print(SharedMutableObject.class_variable) # ここ
400
+
401
+
402
+
403
+
404
+
405
+ b = SharedMutableObject()
406
+
407
+ b.instance_variable = b.class_variable
408
+
409
+
410
+
411
+ a.instance_variable["state"] = "second"
412
+
413
+
414
+
415
+ print(b.class_variable) # ここ
416
+
417
+ print(SharedMutableObject.class_variable) # ここ
418
+
419
+ ```

6

些細

2021/05/16 23:39

投稿

quickquip
quickquip

スコア11038

test CHANGED
@@ -350,8 +350,6 @@
350
350
 
351
351
  a = [1, 3, 2, 4]
352
352
 
353
-
354
-
355
353
  b = a
356
354
 
357
355
 

5

追記

2021/05/16 15:16

投稿

quickquip
quickquip

スコア11038

test CHANGED
@@ -311,3 +311,57 @@
311
311
  print(b.x) # => bに属性xがないので、次にクラスの属性xを探す。1に束縛されているので1がプリントされる
312
312
 
313
313
  ```
314
+
315
+
316
+
317
+ ----
318
+
319
+ (追記)
320
+
321
+
322
+
323
+ もう一段基本的なことを確認しておきたいんですが、
324
+
325
+
326
+
327
+ ```python
328
+
329
+ a = {}
330
+
331
+ b = a
332
+
333
+
334
+
335
+ a['x'] = 1
336
+
337
+
338
+
339
+ print(b)
340
+
341
+ ```
342
+
343
+
344
+
345
+ とか
346
+
347
+
348
+
349
+ ```python
350
+
351
+ a = [1, 3, 2, 4]
352
+
353
+
354
+
355
+ b = a
356
+
357
+
358
+
359
+ a.sort()
360
+
361
+
362
+
363
+ print(b)
364
+
365
+ ```
366
+
367
+ の結果は、実行せずにすぐ想像できるんでしょうか?

4

修正

2021/05/16 15:16

投稿

quickquip
quickquip

スコア11038

test CHANGED
@@ -308,6 +308,6 @@
308
308
 
309
309
  print(a.x) # => aに属性xがあって10に束縛されているので10がプリントされる
310
310
 
311
- print(b.z) # => bに属性xがないので、次にクラスの属性xを探す。1に束縛されているので1がプリントされる
311
+ print(b.x) # => bに属性xがないので、次にクラスの属性xを探す。1に束縛されているので1がプリントされる
312
-
312
+
313
- ```
313
+ ```

3

追記

2021/05/16 02:02

投稿

quickquip
quickquip

スコア11038

test CHANGED
@@ -105,3 +105,209 @@
105
105
 
106
106
 
107
107
  `__dict__`を使った話が理解できるのは、まずこれらが分かってからかと思いますが大丈夫でしょうか。
108
+
109
+
110
+
111
+
112
+
113
+ ----
114
+
115
+ (追記)
116
+
117
+
118
+
119
+ もう一段基本的な方からいきましょう。
120
+
121
+
122
+
123
+ Pythonでは、「自分で宣言したクラス」のインスタンスに対して、`インスタンス.属性 = 値`という代入文で**そのインスタンス**になにかの値に属性を束縛できます。
124
+
125
+
126
+
127
+ ```python
128
+
129
+ class Foo:
130
+
131
+ pass
132
+
133
+
134
+
135
+ a = Foo()
136
+
137
+ a.x = 1
138
+
139
+ a.y = 2
140
+
141
+
142
+
143
+ b = Foo()
144
+
145
+ b.y = 3
146
+
147
+
148
+
149
+ print(a.x) # => 1がプリントされる
150
+
151
+ print(a.y) # => 2がプリントされる
152
+
153
+ print(b.x) # => 3がプリントされる
154
+
155
+ print(b.y) # => エラー
156
+
157
+ ```
158
+
159
+
160
+
161
+ です。
162
+
163
+ `a.x`と`b.x`の値が異なることから、属性はインスタンス毎に付けることが分かります。
164
+
165
+ これがインスタンス変数です。
166
+
167
+
168
+
169
+ (脱線しますが、intやlistのようなPython言語のコアな組み込み型ではこの機構はありません。勝手に属性を追加されたりすると困るので)
170
+
171
+
172
+
173
+ クラス定義の外では、クラスに対して、`クラス.属性 = 値`という代入文で**そのクラス**になにかの値に属性を束縛できます。
174
+
175
+
176
+
177
+ ```python
178
+
179
+ Foo.c = 1
180
+
181
+
182
+
183
+ print(Foo.c) # => 1がプリントされる
184
+
185
+ print(Foo.d) # => エラー
186
+
187
+ ```
188
+
189
+
190
+
191
+ "クラス定義の外では"とわざわざ注釈を入れたのは、クラス定義の中では書けないからです。
192
+
193
+
194
+
195
+ ```Python
196
+
197
+ class Bar:
198
+
199
+ Bar.c = 1 # => エラー
200
+
201
+ ```
202
+
203
+ なぜかというと、Barという名前はclass文の**実行が終わった時**にできる名前だからです。
204
+
205
+ 実行が終わってないところでは使えません。
206
+
207
+
208
+
209
+ どうするかというと
210
+
211
+
212
+
213
+ ```Python
214
+
215
+ class Bar:
216
+
217
+ c = 1
218
+
219
+
220
+
221
+ print(Bar.c) # => 1
222
+
223
+ ```
224
+
225
+ とします。
226
+
227
+
228
+
229
+ [https://docs.python.org/ja/3/tutorial/classes.html#class-objects](https://docs.python.org/ja/3/tutorial/classes.html#class-objects)
230
+
231
+ > クラスオブジェクトが生成された際にクラスの名前空間にあった名前すべてが有効な属性名です。
232
+
233
+
234
+
235
+ クラス宣言の実行部分で名前`c`が作られましたから、クラスBarは属性名cを持ちます
236
+
237
+ ということです。
238
+
239
+
240
+
241
+ ```Python
242
+
243
+ class Bar:
244
+
245
+ c = 1
246
+
247
+ ```
248
+
249
+
250
+
251
+ ```python
252
+
253
+ class Bar:
254
+
255
+ pass
256
+
257
+ Bar.c = 1
258
+
259
+ ```
260
+
261
+ は(実行される順番は違うけれども)結果が同じになります。
262
+
263
+
264
+
265
+ ----
266
+
267
+ ここまで分かったら
268
+
269
+
270
+
271
+ [いろいろな注意点](https://docs.python.org/ja/3/tutorial/classes.html#random-remarks) に
272
+
273
+ > インスタンスとクラスの両方で同じ属性名が使用されている場合、属性検索はインスタンスが優先されます。
274
+
275
+
276
+
277
+ とありますが、
278
+
279
+ 「インスタンスとクラスの両方で同じ属性を持っていればインスタンスが優先されます」という説明は、裏から言うと
280
+
281
+ `インスタンス.属性`という形でアクセスする時、インスタンスがその属性を持っていなければ**クラスの属性を見つけてくる**
282
+
283
+
284
+
285
+ と書いたのが分かるはずです。
286
+
287
+
288
+
289
+
290
+
291
+ ```python
292
+
293
+ class Bazz:
294
+
295
+ x = 1
296
+
297
+
298
+
299
+ a = Bazz()
300
+
301
+ a.x = 10
302
+
303
+
304
+
305
+ b = Bazz()
306
+
307
+
308
+
309
+ print(a.x) # => aに属性xがあって10に束縛されているので10がプリントされる
310
+
311
+ print(b.z) # => bに属性xがないので、次にクラスの属性xを探す。1に束縛されているので1がプリントされる
312
+
313
+ ```

2

追記

2021/05/16 02:00

投稿

quickquip
quickquip

スコア11038

test CHANGED
@@ -64,6 +64,8 @@
64
64
 
65
65
  print(Fuga.shared_list) # Fuga.shared_listは[1, 1]なので[1, 1]がprintされる
66
66
 
67
+ print(b.shared_list) # shared_listがインスタンス属性から見つからないので、Fuga.shared_listが探索され、[1, 1]なので[1, 1]がprintされる
68
+
67
69
  ```
68
70
 
69
71
 

1

リンク追加

2021/05/15 16:08

投稿

quickquip
quickquip

スコア11038

test CHANGED
@@ -1,4 +1,4 @@
1
- まず(`__dict__`は完全に忘れて)普通のクラス変数の取り扱いは分かるでしょうか。
1
+ まず(`__dict__`は完全に忘れて)普通の[クラス変数](https://docs.python.org/ja/3/tutorial/classes.html#class-objects)の取り扱いは分かるでしょうか。
2
2
 
3
3
  ```python
4
4
 
@@ -68,9 +68,7 @@
68
68
 
69
69
 
70
70
 
71
- [クラスとインスタンス変数](https://docs.python.org/ja/3/tutorial/classes.html#class-and-instance-variables)
71
+ [クラスとインスタンス変数](https://docs.python.org/ja/3/tutorial/classes.html#class-and-instance-variables)
72
-
73
-
74
72
 
75
73
  > 名前とオブジェクトについて で議論したように、共有データはリストや辞書のような mutable オブジェクトが関与すると驚くべき効果を持ち得ます。
76
74
 
@@ -86,9 +84,7 @@
86
84
 
87
85
 
88
86
 
89
- [いろいろな注意点](https://docs.python.org/ja/3/tutorial/classes.html#random-remarks)
87
+ [いろいろな注意点](https://docs.python.org/ja/3/tutorial/classes.html#random-remarks)
90
-
91
-
92
88
 
93
89
  > インスタンスとクラスの両方で同じ属性名が使用されている場合、属性検索はインスタンスが優先されます。
94
90