星期五, 十一月 23, 2007

python class methods identity

对于 Python Tree,有个问题我一直很担心,就是每个 Tree instance 会占用多少内存?Python 下面似乎是没有 sizeof() 这样的东西。

最主要的一个问题是,每个 Tree instance 都包含了在 class 中定义的那些方法以及一些全局变量,每个 instance 自身的变量其实只有 _Tree__node_value 和 _Tree__node_items。

这样,我就需要查看一下所有的 instance 的类全局变量和方法是否都使用共享的内存:
>>> import tree
>>> a = tree.Tree(1)
>>> b = tree.Tree(2)
>>> a.__call__ is b.__call__
False
>>> dir(a)
['_Tree__id_visited', '_Tree__node_items', '_Tree__node_value', '_Tree__path_stack', '_Tree__used_names', '__add__', '__call__', '__cmp__', '__contains__', '__doc__', '__getitem__', '__has__', '__iadd__', '__init__', '__islike__', '__issame__', '__module__', '__search__', '__setattr__', '__setitem__', '__str__', '__traverse__', '__update__', '_one_node_get', '_one_node_set']
>>> a._Tree__node_value is b._Tree__node_value
False
>>> a.__dict__
{'_Tree__node_items': {}, '_Tree__node_value': 1}
>>> a._Tree__id_visited is b._Tree__id_visited
True
>>> a.__module__ is b.__module__
True
>>> a.__add__ is b.__add__
False
方法 is identity 检查结果是 false。那么是不是每个 instance 都是以不同的函数栈而并不共享呢?

看一个简单的例子:
>>> class Test:
... var = 1
... def func(self): pass
...
>>> x = Test()
>>> y = Test()
>>> x.var is y.var
True
>>> x.func is y.func
False
>>> id(x.var); id(y.var)
146132400
146132400
>>> id(x.func); id(y.func)
-1208243388
-1208243388
这里 id(x.func) 和 id(y.func) 的返回值一样。根据 help(id):
Help on built-in function id in module __builtin__:

id(...)
id(object) -> integer

Return the identity of an object. This is guaranteed to be unique among
simultaneously existing objects. (Hint: it's the object's memory address.)
它们应该是同一个对象,那为什么 is 检测返回 False 呢?

从 python-chinese@lists.python.cn 上得到了答案:

>>> dir(x.func)
['__call__', '__class__', '__cmp__', '__delattr__', '__doc__', '__get__', '__getattribute__', '__hash__', '__init__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__str__', 'im_class', 'im_func', 'im_self']
>>> id(x.func.im_func)
-1210950828
>>> id(y.func.im_func)
-1210950828
>>> id(y.func.im_self)
-1208531092
>>> id(x.func.im_self)
-1208581588
这也就是说,is 检测到了 im_self 的差异,所以返回 False。而 im_self 其实就是拥有这个 func 的 instance object,而 im 应该就是指 instance method。

不过在 Windows 下运行的结果却是不同的(IDLE):
>>> class Test:
var = 1
def func(self): pass


>>> x = Test()
>>> y = Test()
>>> id(x.var)
11228488
>>> id(y.var)
11228488
>>> id(x.func)
14432856
>>> id(y.func)
14368816

没有评论: