2010-10-19 08:49:20| 分類: 技術文章 | 標簽:class 動態增加屬性 python |舉報|字號 訂閱
在python里如何動態添加類的動態屬性呢?看下面的例子
class A(object):
a = 1
b = 2
def fun1(self):
print 'fun1'
def fun2(self):
print 'fun2'
a1 = A()
a1.c = 1
這里我們定義了一個類A,還有一個實例a1。a1.c = 1 只是增加實例的屬性而不是增加類的屬性。
我們知道python對象有一__dict__屬性,那我們嘗試這樣操作:
setattr( A.__dict__, 'd', 1)
這樣的操作會得到一下的錯誤:
TypeError: 'dictproxy' object has only read-only attributes (assign to .d)
這是什么意思呢?其實python對象里的獲取“__dict__”屬性,實際上獲取的並不是實際的dict,獲取的只是一個dictproxy。
在源碼里typeobject.c里
static PyGetSetDef type_getsets[] = {
{"__name__", (getter)type_name, (setter)type_set_name, NULL},
{"__bases__", (getter)type_get_bases, (setter)type_set_bases, NULL},
{"__module__", (getter)type_module, (setter)type_set_module, NULL},
{"__dict__", (getter)type_dict, NULL, NULL},
{"__doc__", (getter)type_get_doc, NULL, NULL},
{0}
};
這里定義了__dict__對應的c的獲取方法。
我們找到type_dict方法的實現
static PyObject *
type_dict(PyTypeObject *type, void *context)
{
if (type->tp_dict == NULL) {
Py_INCREF(Py_None);
return Py_None;
}
return PyDictProxy_New(type->tp_dict);
}
可以看到其實每次獲取__dict__熟悉時,都是new一個dictproxy。
正確的操作應該是:
setattr( A, 'd', 1)
或者
setattr( a1.__class__, 'd', 1)
具體實現可以看classobject.c里的方法:
static int class_setattr(PyClassObject *op, PyObject *name, PyObject *v)
該函數會對非“__”開頭的屬性自動轉到op->tp_dict。
