pythonで関数ポインタのようなことをしたいのですが
ただの関数であれば正しく参照されるのですが
クラスのインスタンスメソッドになると正しく参照されないです。
何故こうなるのか教えてほしいです。
ただの関数の場合、出力結果は同じになりました。
python
1def b(): 2 print('b') 3 4refb = b 5print(id(b)) 6print(id(refb))
インスタンスメソッドの場合、出力結果が異なります。
python
1class A(): 2 def __init__(self): 3 refx=self.x 4 print(id(self.x)) 5 print(id(refx)) 6 def x(self): 7 print("x") 8a=A()
バージョン:python3.6.1
よろしくお願いします。
気になる質問をクリップする
クリップした質問は、後からいつでもMYページで確認できます。
またクリップした質問に回答があった際、通知やメールを受け取ることができます。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
回答3件
0
ベストアンサー
リファレンスで下記のような記述を見つけました。
3. データモデル — Python 3.9.0 ドキュメント の「インスタンスメソッド」の項。
なお、関数オブジェクトからインスタンスメソッドオブジェクトへの変換は、インスタンスから属性が取り出されるたびに行われます。場合によっては、属性をローカル変数に代入しておき、そのローカル変数を呼び出すようにするのが効果的な最適化になります。
この項全体を読むのが良いと思いますが、self.x
という属性参照する度に新たに「インスタンスメソッドオブジェクト」が生成されるようです。
投稿2020/10/16 22:38
編集2020/10/16 23:50総合スコア85901
0
回答が間違っていましたので、解決済ですが修正します。
・・・という回答も間違っていたので再度修正します。
@otn様の回答で合っているのですが、私がその回答の理解に手間取りました。参考になるかもしれませんので記載します。
まず@otn様の回答にありますように、「関数オブジェクトからインスタンスメソッドオブジェクトが毎回生成される」ことになります。具体的に今回の場合にはclass 'function'>であるA.x
とclass '__main__.A'>であるself
から<class 'method'>であるself.x
が新規生成されます。以下のコードの実行でそれがわかります。
ですので、「コードの中のself.xは全て新規生成されたオブジェクト」になっています。
よって、以下のコードで、self.xとrefxとrefx2が別IDになります。細かく言うと、print(type(self.x), id(self.x))
の中の2箇所のself.xも、別オブジェクトになっているはずです。
ところが、以下のコードで**refx3 = refx
ではオブジェクトの新規生成は行われません。よってそれぞれの変数に同一のオブジェクトが代入され、IDは同一になります**。
わかりにくいのが、以下のコードの2番目のprint(type(self.x), id(self.x))
です。別オブジェクトのはずなのに、前と同じIDを示しています。これは、同一の識別子の変数への代入では、Python環境によっては、オブジェクトのIDを使い回す可能性があるためです。性能改善やメモリ効率化のためだと思われます。この動作はPython環境依存です。質疑において、別の方とIDの出方(前と同じか異なるか)が食い違ったため、環境依存であるとわかりました。なお、識別子が同じでIDを使い回す場合に、インスタンスメソッドオブジェクトが毎回同じIDで新規作成されるのか、それとも以前のオブジェクトを新しい変数(識別子は同じ)に代入して使い回すのか、はたまた変数そのものも同一なのか、は厳密には謎です。最初の方が汎用的ですが、実装依存で高速性を追求して、2番目以降の可能性もあります。
Python
1class A(): 2 def __init__(self): 3 refx=self.x 4 refx2=self.x 5 print(type(A.x)) 6 #<class 'function'> 7 print(type(self)) 8 #<class '__main__.A'> 9 print(type(self.x), id(self.x)) 10 #<class 'method'> 140270956725312 11 print(type(refx), id(refx)) 12 #<class 'method'> 140270936531840 13 print(type(refx2), id(refx2)) 14 #<class 'method'> 140270936573056 15 refx3 = refx 16 print(type(refx3), id(refx3)) 17 #<class 'method'> 140270936531840 18 print(type(self.x), id(self.x)) 19 #<class 'method'> 140270956725312 20 def x(self): 21 print("x") 22 23refa=A()
投稿2020/10/16 16:43
編集2020/10/17 09:45総合スコア3266
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2020/10/17 03:34
2020/10/17 03:42
2020/10/17 03:57 編集
2020/10/17 03:57 編集
2020/10/17 04:02
2020/10/17 04:03
2020/10/17 04:35 編集
2020/10/17 04:49
2020/10/17 05:01
2020/10/17 05:06
2020/10/17 05:12
2020/10/17 05:39
2020/10/17 07:54
2020/10/17 08:26
2020/10/17 08:34
2020/10/17 08:51
2020/10/17 08:56
あなたの回答
tips
太字
斜体
打ち消し線
見出し
引用テキストの挿入
コードの挿入
リンクの挿入
リストの挿入
番号リストの挿入
表の挿入
水平線の挿入
プレビュー
質問の解決につながる回答をしましょう。 サンプルコードなど、より具体的な説明があると質問者の理解の助けになります。 また、読む側のことを考えた、分かりやすい文章を心がけましょう。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2020/10/17 01:56