Pythonクイズの答え
http://d.hatena.ne.jp/mopemope/20081017/p1
>>> import types
>>> class A(object):pass
...
>>> def test(self):
... print "test"
...
>>> a = A()
>>> a.test = types.MethodType(test, a, a.__class__)
>>> a.test
>
>>> a.test()
test
>>> b = A()
>>> b.test()
Traceback (most recent call last):
File "", line 1, in
AttributeError: 'A' object has no attribute 'test'
>>>
newモジュールってあったよね、ってのを思い出して書いてみました。
newモジュールは3.0でなくなってしまうのでtypesを使う方を回答としています。
newモジュールを使用しているライブラリにはsetuptoolsなどがあります。
id:jbkingさん、id:morchinさん、id:odzさん回答ありがとうございました。
typeオブジェクト
typeオブジェクトはそのtypeのインスタンスを生成するファクトリとして機能します。
>>> import types
>>> types.IntType
>>> i = types.IntType(1)
>>> i
1
>>> type(i)
>>>
ClassType, UnboundMethodType,InstanceType,MethodTypeなどは
types.py
class _C: def _m(self): pass ClassType = type(_C) UnboundMethodType = type(_C._m) # Same as MethodType _x = _C() InstanceType = type(_x) MethodType = type(_x._m)
のようになっています。
しかしこの状態だとイマイチなんで引数が(関数、インスタンス、クラス)なのかがわかりませんね。
typeはどこに?
実際これらtypeからインスタンス生成を生成するコードはCで書かれています。
pythonのオブジェクトシステム関連のソースはpythonのsrcのObject以下に入っています。
pythonの拡張モジュールを書いた事がある人は知っているかも知れませんがPyTypeObject
を定義する時に
0, /* tp_methods */ 0, /* tp_members */ 0, /* tp_getset */ 0, /* tp_base */ 0, /* tp_dict */ 0, /* tp_descr_get */ 0, /* tp_descr_set */ 0, /* tp_dictoffset */ 0, /* tp_init */ 0, /* tp_alloc */ instance_new, /* tp_new */
type関連の関数をセットします。
tp_newの箇所がそのtypeを生成する関数になります。
インスタンスメソッドであるMethodTypeは以下のようになってます。
python2.6のObject/classobject.c
2610 PyTypeObject PyMethod_Type = { 2611 PyObject_HEAD_INIT(&PyType_Type) 2612 0, 2613 "instancemethod", 2614 sizeof(PyMethodObject), 2615 0, 2616 (destructor)instancemethod_dealloc, /* tp_dealloc */ 2617 0, /* tp_print */ 2618 0, /* tp_getattr */ 2619 0, /* tp_setattr */ 2620 (cmpfunc)instancemethod_compare, /* tp_compare */ 2621 (reprfunc)instancemethod_repr, /* tp_repr */ 2622 0, /* tp_as_number */ 2623 0, /* tp_as_sequence */ 2624 0, /* tp_as_mapping */ 2625 (hashfunc)instancemethod_hash, /* tp_hash */ 2626 instancemethod_call, /* tp_call */ 2627 0, /* tp_str */ 2628 instancemethod_getattro, /* tp_getattro */ 2629 PyObject_GenericSetAttr, /* tp_setattro */ 2630 0, /* tp_as_buffer */ 2631 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_HAVE_WEAKREFS, /* tp_flags */ 2632 instancemethod_doc, /* tp_doc */ 2633 (traverseproc)instancemethod_traverse, /* tp_traverse */ 2634 0, /* tp_clear */ 2635 0, /* tp_richcompare */ 2636 offsetof(PyMethodObject, im_weakreflist), /* tp_weaklistoffset */ 2637 0, /* tp_iter */ 2638 0, /* tp_iternext */ 2639 0, /* tp_methods */ 2640 instancemethod_memberlist, /* tp_members */ 2641 instancemethod_getset, /* tp_getset */ 2642 0, /* tp_base */ 2643 0, /* tp_dict */ 2644 instancemethod_descr_get, /* tp_descr_get */ 2645 0, /* tp_descr_set */ 2646 0, /* tp_dictoffset */ 2647 0, /* tp_init */ 2648 0, /* tp_alloc */ 2649 instancemethod_new, /* tp_new */ 2650 };
tp_newはinstancemethod_newとなっています。
2330 static PyObject * 2331 instancemethod_new(PyTypeObject* type, PyObject* args, PyObject *kw) 2332 { 2333 PyObject *func; 2334 PyObject *self; 2335 PyObject *classObj = NULL; 2336 2337 if (!_PyArg_NoKeywords("instancemethod", kw)) 2338 return NULL; 2339 if (!PyArg_UnpackTuple(args, "instancemethod", 2, 3, 2340 &func, &self, &classObj)) 2341 return NULL; 2342 if (!PyCallable_Check(func)) { 2343 PyErr_SetString(PyExc_TypeError, 2344 "first argument must be callable"); 2345 return NULL; 2346 } 2347 if (self == Py_None) 2348 self = NULL; 2349 if (self == NULL && classObj == NULL) { 2350 PyErr_SetString(PyExc_TypeError, 2351 "unbound methods must have non-NULL im_class"); 2352 return NULL; 2353 } 2354 2355 return PyMethod_New(func, self, classObj); 2356 }
instancemethod_newはPyMethod_Newを呼び出します。
2225 PyObject * 2226 PyMethod_New(PyObject *func, PyObject *self, PyObject *klass) 2227 { 2228 register PyMethodObject *im; 2229 if (!PyCallable_Check(func)) { 2230 PyErr_BadInternalCall(); 2231 return NULL; 2232 }
ここまでくると引数に何を渡しているのかわかりますね。
ちなみにpython3.0では最後のclassは渡さなくてもよくなります。
42 PyObject * 43 PyMethod_New(PyObject *func, PyObject *self) 44 { 45 register PyMethodObject *im; 46 if (!PyCallable_Check(func)) {
そもそもpython3.0ではクラス周りに色々手が入っているようです。
type、結合メソッド、非結合メソッドなど以下の書籍に詳しく書かれているので読んでみるといいかも知れません。
- 作者: アレックスマーテリ,Alex Martelli,クイープ
- 出版社/メーカー: オライリージャパン
- 発売日: 2004/03/01
- メディア: 単行本
- 購入: 2人 クリック: 158回
- この商品を含むブログ (25件) を見る