質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.50%
Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

Q&A

解決済

2回答

10667閲覧

[python]dict型を継承したクラスの、初期化時の挙動について

nikori

総合スコア19

Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

0グッド

0クリップ

投稿2018/01/10 02:12

Pythonを学習し始めたばかりの初学者です。

以下のようにdict型を継承するクラスを作成したところ、dict型に値が格納されないという予期しない挙動を示しました。

Coinsクラスは各Coinを何枚所持しているかをdict型で保持するクラスです。
python3.6を利用しています。

python

1#ERROR CODE 2class Coin(IntEnum): 3 YEN_100 = 100 4 YEN_500 = 500 5 6class Coins(dict): 7 def __init__(self, numberOfCoins): 8 self = {} 9 coinID = 0 10 for coin in Coin: 11 self.update({coin : numberOfCoins[coinID]}) 12 print(self[coin]) 13 coinID += 1 14 15myCoins = Coins([3,2]) 16print(myCoins) # => {}が表示

実験の結果
Coinsクラスのコンストラクタ中で、self = {}を削除すると期待した挙動をすることが分かりました。

python

1class Coin(IntEnum): 2 YEN_100 = 100 3 YEN_500 = 500 4 5class Coins(dict): 6 def __init__(self, numberOfCoins): 7 #self = {} 8 coinID = 0 9 for coin in Coin: 10 self.update({coin : numberOfCoins[coinID]}) 11 print(self[coin]) 12 coinID += 1 13 14myCoins = Coins([3,2]) 15print(myCoins) # => {<Coin.YEN_100: 100>: 3, <Coin.YEN_500: 500>: 2}が表示

この挙動がなぜ起こるのか、理解ができなかったため質問させていただきました。
ご存知の方がいらっしゃいましたらよろしくお願いします。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答2

0

親の__init__を呼んであげると良いです。

python

1class Coins(dict): 2 def __init__(self, numberOfCoins): 3 dict.__init__(self)

投稿2018/01/10 02:46

YouheiSakurai

総合スコア6142

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

nikori

2018/01/10 02:47

ありがとうございます! 継承を使う場合、super()で親の__init__を使うようにと学んだことを失念しておりました。
guest

0

ベストアンサー

冒頭にself = {}を入れたら、今初期化しようとしている《Coinsクラスのインスタンス》とは何の関係もないdictのインスタンス(右辺の{}のことです)に値をセットしていることになりますよね。

余談ながら、__init__はコンストラクタではないですよ。__new__がコンストラクタで、__init__は「コンストラクタが返した値を初期化する」ためのものです。
http://docs.python.jp/3/reference/datamodel.html#object.init

投稿2018/01/10 02:32

quickquip

総合スコア11029

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

nikori

2018/01/10 02:46

selfは予約語ではなく、呼び出したインスタンスが第一引数(self)に格納されるという仕様によるものなのですね。 self = {}を書くと、selfがインスタンスを参照しなくなるのだと理解しました。 __init__について完全に勘違いしていました。ご指摘ありがとうございます。
quickquip

2018/01/10 02:55

「呼び出したインスタンス」よりは「生成されたインスタンス」の方が誤解は少ないかと。 例えば、Coins(a, b) を 呼び出すと、コンストラクタ Coins.__init__(Coins, a, b) がまず呼び出されて、いろいろあって Coins のインスタンスが作られます。 そのあと Coins.__init__(生成されたインスタンス, a, b) が呼び出されます。呼び出された __init__ から見ると、第1引数に「生成されたインスタンス」が渡ってきています。 それをローカル変数(名)のselfにバインドしろ、と宣言しているのでselfが「生成されたインスタンス」を指しています。 selfは慣習上そう書いているだけで「ただのローカル変数」でしかありません。
nikori

2018/01/10 03:17

なるほど、生成されたインスタンスという方が適切ですね。 大変勉強になりました。ありがとうございました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.50%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問