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

回答編集履歴

11

少し追記

2021/05/19 03:57

投稿

quickquip
quickquip

スコア11314

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

些細

2021/05/19 03:57

投稿

quickquip
quickquip

スコア11314

answer CHANGED
@@ -186,7 +186,7 @@
186
186
 
187
187
  (追記)
188
188
 
189
- では以上を合わせれの結果も実行せずにわかるはず。
189
+ では以上の挙動すべ理解できていば、下の結果も実行せずにわかるはずです
190
190
 
191
191
  ```python
192
192
  class SharedMutableObject:

9

代入の変更

2021/05/19 03:45

投稿

quickquip
quickquip

スコア11314

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(b.class_variable) # ここ
206
+ print(a.class_variable) # ここ
209
207
  print(SharedMutableObject.class_variable) # ここ
210
208
  ```

8

追記

2021/05/16 23:50

投稿

quickquip
quickquip

スコア11314

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

追記

2021/05/16 23:47

投稿

quickquip
quickquip

スコア11314

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

些細

2021/05/16 23:39

投稿

quickquip
quickquip

スコア11314

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

追記

2021/05/16 15:16

投稿

quickquip
quickquip

スコア11314

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

修正

2021/05/16 15:16

投稿

quickquip
quickquip

スコア11314

answer CHANGED
@@ -153,5 +153,5 @@
153
153
  b = Bazz()
154
154
 
155
155
  print(a.x) # => aに属性xがあって10に束縛されているので10がプリントされる
156
- print(b.z) # => bに属性xがないので、次にクラスの属性xを探す。1に束縛されているので1がプリントされる
156
+ print(b.x) # => bに属性xがないので、次にクラスの属性xを探す。1に束縛されているので1がプリントされる
157
157
  ```

3

追記

2021/05/16 02:02

投稿

quickquip
quickquip

スコア11314

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

追記

2021/05/16 02:00

投稿

quickquip
quickquip

スコア11314

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

リンク追加

2021/05/15 16:08

投稿

quickquip
quickquip

スコア11314

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
  とありますが、