5倍速!メールマガジン
外部アカウントで登録
受講生の声
新着の講座投稿
新着の講座コメント
新着のノート投稿
投稿一覧へ新着のノートコメント
表示できる投稿はありません。
サイト運営者紹介
小川 慶一講師/教材/システム開発者紹介
この学習サイトの教材制作、サポート、システム開発をすべてやっています。
表示できる投稿はありません。
この学習サイトの教材制作、サポート、システム開発をすべてやっています。
藤本 博子さんの投稿
(投稿ID: 5419)
お手数をおかけしますが、どうぞよろしくお願いいたします。
※クラスとインスタンスのread.mdのサンプルコードP9とサンプルコード「part09_43_class_method.py」21行目にかかれた、インスタンス変数でクラスメソッドを実行しているコードについて
生成したインスタンス「silver」を@classmethod def get_asset_type(cls):を実行するメソッドがかかれています。
・クラスメソッドはクラスをインスタンス化せずに実行するメソッド
動画でも、class Metalでメソッドを実行するデモでした。
しかし、サンプルコードとread.mdには上記のメソッドが書かれてました。
・インスタンス変数(silver)を生成したときは、コンストラクタで属性を初期化するか、
インスタンスメソッドを使用すると理解してました。
(1)__init__メソッドのコンストラクタでasset_typeを引数type_nameの値で設定する
(2)もしくは、インスタンスメソッド(第一引数self)で設定
インスタンス変数に対して、クラスメソッドを実行することがあるのかな…と思ったため、ご教示いただけると、ありがたいです。
・Metal.set_asset_type('地金')の式を実行しても、インスタンス変数でsilverのasset_typeの属性を"silver"で設定した値が維持される。
・インスタンス変数silverでクラスメソッドを実行すると、クラスメソッドで設定した属性が設定される。
お手数をおかけしますが、どうぞよろしくお願いいたします。
小川 慶一さんのコメント
(コメントID: 7955)
さすが、鋭い...ですね (^^;
まず、大原則を示します。
なお、以下で、「属性」とは、変数/メソッドの両方をひっくるめた言い方です。(念のため)
[1] インスタンスは、インスタンス属性にアクセスできる。
[2] インスタンスは、クラス属性にアクセスできる。
[3] クラスは、クラス属性にアクセスできる。
[4] クラスは、インスタンスにアクセスできない
[2] については、クラス属性と同名のインスタンス属性がある場合、インスタンスは、インスタンス属性のほうにアクセスします。
ここで、「では、クラス属性と同名のインスタンス属性がある場合、インタンスは、どうやってクラス属性にアクセスするのだ?」という問題があります。
これについては、「属性」とひとくくりにせず、以下の2つに分けて解説します。
[2-1] クラス変数と同名のインスタンス変数がある場合
[2-2] クラスメソッドと同名のインスタンスメソッドがある場合
[2-1] については、まず、クラス変数にアクセスするときは、 .__class__ 属性経由でなんとかなります:
[2-2] については、「手練れの技」的なものを駆使すればおもしろい実験もできないことはないのですが...。クラス/インスタンスの挙動にかなり慣れた方でないとソースを読んでも混乱するばかりなので、ここでは説明を省きます。
今回は、「以下のように同名のメソッドを同一クラス内で複数定義するのは無理」ということだけ覚えておいてください。[a] と [b] のどちらが後に書かれているかによって実行結果が変わります。後に定義されたものが残ります。
以下では、後に書かれた [b] が実行されます。
もしも [a] と [b] の位置を入れ替えると、エラーが出るようになります。(エラーになるのは、 [4] で説明したとおり、 [a] はインスタンスメソッドなので、クラスからは呼び出せないからです)
「後に定義されたものが残る」なら、「前に定義さたもの」は、まるまる無駄ですし、コードを読む人を混乱させるだけですね。
ということで、まずは、この説明でいかがでしょうか。
なお、上記 [2-1], [2-2] のような話は、キワキワなケースの件です。
上記のような .__class__ を経由しないとアクセスできないようなものにアクセスする必要があるコードを書かなくてはならないとしたら、そもそも設計を見直したほうがよいです。
実際、僕自身、自分が書いたクラスに対してインスタンスがこういうコードでクラス属性にアクセスするようなコードを書くことはありません。
人が作ったライブラリを利用するコードを書くときに、仕方なくやることがたまにあるくらいですね。
まずは、以上のとおりです。
藤本 博子さんのコメント
(コメントID: 7958)
丁寧に紐解き、解説くだしまして、ありがとうございました。
>「属性」とは、変数/メソッドの両方をひっくるめた言い方です。(念のため)
属性が変わる、と安易な言い方をしておりました。
クラス変数の動画を見直し、先生がクラスのプロパティが変更される際、どのような表現をされているか見直しました。
あと、以下の説明についても、コードと解説いただいたことにより、腑に落ちました。
>もしも [a] と [b] の位置を入れ替えると、エラーが出るようになります。(エラーになるのは、 [4] で説明したとおり、 [a] はインスタンスメソッドなので、クラスからは呼び出せないからです)
>「後に定義されたものが残る」なら、「前に定義さたもの」は、まるまる無駄ですし、コードを読む人を混乱させるだけですね。
今回ご教示いただたいたこと、動画見直ししたことで理解が深まりました。
本当にありがとうございます!!
藤本 博子さんのコメント
(コメントID: 7959)
@classmethod def my_method(self): #[b]の第一引数(self)は、第一引数を(cls)にしても同じ結果になるのですが、今回の事例で分かりやすいようselfにしていただいたのかなぁ、と思いました。
クラスメソッドの動画で、第一引数をclsにしなくてもよいけれども、clsとするのがよい、と教えていただきました。
小川 慶一さんのコメント
(コメントID: 7960)
すいません。これは、僕のうっかりミスです。
元投稿内のコードを修正しておきました。
ご指摘、ありがとうございます m(_ _)m
藤本 博子さんのコメント
(コメントID: 7963)
「インスタンス作成の演習1」 27:00あたり
・クラス変数(list)"allowed_types"を生成
・コンストラクタ呼び出し時に、受け取った引数"type_name"の値が、list"allowd_types"以外の場合は例外の処理をする。というコードがでてきます。
self.allowed_typesと書くことでクラス属性にアクセスしていることを理解しつつつ、学習をすすめることができました。
self.__class__.allowed_typesと書いても動く
[1] インスタンスは、インスタンス属性にアクセスできる。
[2] インスタンスは、クラス属性にアクセスできる。
[3] クラスは、クラス属性にアクセスできる。
[4] クラスは、インスタンスにアクセスできない
ありがとうございました。
ありがとうございました。
小川 慶一さんのコメント
(コメントID: 7964)
こんばんは。
ちょっと気になるので...以下、サンプルコードです。
クラス変数と同名のインスタンス変数を作ることができます。([1])
そのとき、インスタンス変数が新たに生成されますが、この生成されたインスタンス変数はクラス変数に影響を与えません。
[1] がないと asset_type という名前のインスタンス変数はないので、 jp_bond.asset_type でアクセスできるのはクラス変数です。
藤本さんの理解と一致しているでしょうか。
override_asset_type.py
以下は、上記コードを実行したときの出力例。
インスタンス変数とクラス変数でidが異なります。違うものを参照しているからです。
以下では、上記 [1] をコメントアウトしました。
そのとき、 jp_bond.asset_type でアクセスしているのは、クラス変数です。
not_override_asset_type.py
以下は、上記コードを実行したときの出力例。
インスタンス変数とクラス変数でidが異なります。違うものを参照しているからです。
両者での出力結果の違いに違和感なければOKです。
藤本 博子さんのコメント
(コメントID: 7965)
ご返事と事例をもとに解説くださいまして、ありがとうございます。
理解に違和感はございません。
>クラス変数と同名のインスタンス変数を作ることができます。([1])
そのとき、インスタンス変数が新たに生成されますが、この生成されたインスタンス変数はクラス変数に影響を与えません。
クラス変数の動画 08:46あたりで学習しました。
silve.asset_type = '私の貴金属'とインスタンスで同名の"asset_type"という変数を定義して、その値を"私の貴金属"とした場合について
・クラスの方が書き換わったのでなく、インスタンスの方に新しい変数"asset_type"という変数ができて、その値が”私の貴金属”に変わった。
・インスタンスが自分で新しく"asset_type"という名前の変数を作った
・よってクラス変数の値は変わらない
・インスタンス変数の値は変わった
動画10:10のあたりでインスタンスからはアクセスできなくなるのか?
アクセスするには__class__メソッドを使うと、もとのクラスの値をアクセスできる
という説明も学習できました。
演習1のクラス変数でallowed_typesとself.allowed_typesのid関数の戻り値を確認してみました。
結果は同じオブジェクトIDでした。
id関数を使って検証しておりませんでした。
確認する方法について復習、気づきをいただくとこができました。
ありがとうございます。