星期一, 六月 18, 2007

python __dict__ && pseudo private attributes

前面为了定义 Tree 结构时谈到,在重新定义了 __setattr__ 之后只能通过 __dict__ 来赋值。在实际使用的过程中,还发现一些 __dict__ 的问题需要搞清楚。

首先 dir() 的输出和 __dict__ 是不同的,例如定义了一个空类 tree 之后,分别查看 dir() 和 __dict__:
>>> class tree
... def __init__(self): pass
...
>>> t = tree()
>>> dir(tree)
['__doc__', '__init__', '__module__']
>>> print tree.__dict__
{'__module__': '__main__', '__doc__': None, '__init__': }
>>> print t.__dict__
{}
>>> t.f = 'testing'
>>> print t.__dict__
{'f': 'testing'}
>>> print tree.__dict__
{'__module__': '__main__', '__doc__': None, '__init__': }
对一个 class object 甚至可以这样赋值:
>>> class tree:
... def __init__(self): pass
...
>>> d = {'a' : 1, 'b' : 2, 'c' : 3}
>>> tree.__dict__.update(d)
>>> print tree.__dict__
{'a': 1, '__module__': '__main__', 'b': 2, 'c': 3, '__doc__': None, '__init__': }
>>> t = tree()
>>> print t.__dict__
{}
>>> t.b
2
下面的问题涉及伪私有变量的使用。

在 class Tree 中,对于节点值和键索引,使用了 __node_value 和 __node_items 这样的变量。于是定义是:
self.__dict__['__node_value'] = value
self.__dict__['__node_items'] = {}
在使用的时候却发现根本没有值,且报错。可以用下面一些例子来说明这种情况:
>>> class test:
... def __init__(self):
... self.__dict__['x'] = 1
... self.__dict__['__node_value'] = 2
...
>>> t = test()
>>> print t.x
1
>>> print t._test__node_value
Traceback (most recent call last):
File "", line 1, in ?
AttributeError: test instance has no attribute '_test__node_value'

>>> class test:
... def __init__(self):
... self.__dict__['x'] = 1
... self.__dict__['__value'] = 2
... self.__dict__['__node_value'] = 3
...
>>> t = test()
>>> print t.x
1
>>> print t.__value
2
>>> print t.__node_value
3
>>> print t.__dict__
{'__node_value': 3, 'x': 1, '__value': 2}

>>> class test:
... def __init__(self):
... self.__dict__['x'] = 1
... self.__dict__['__node_value'] = 2
... print self.x
... print self.__node_value
...
>>> t = test()
1
Traceback (most recent call last):
File "", line 1, in ?
File "", line 7, in __init__
AttributeError: test instance has no attribute '_test__node_value'

>>> class test:
... def __init__(self):
... self.__dict__['x'] = 1
... self.__node_value = 2
... print self.x
... print self.__node_value
...
>>> t = test()
1
2
>>> print t.__dict__
{'x': 1, '_test__node_value': 2}
可见,当使用 self.__node_value 来赋值时,实际上在 __dict__ 中的键值确实 '_test__node_value',而不是 '__node_value';如果键值是 '__node_value',那么就可以使用 t.__node_value 来访问,而不受所谓 pseudo private attribute 规则的限制!

对于定义在 class object 中的变量也是一样的道理:
>>> class test:
... __used_names = ['name1', 'name2']
... def __init__(self): self.__dict__['x'] = 1
>>> t = test()
>>> print t.__dict__
{'x': 1}
>>> print t.__class__.__dict__
{'__module__': '__main__', '__init__': , '_test__used_names': ['name1', 'name2'], '__doc__': None}
>>> print t.__used_names
Traceback (most recent call last):
File "", line 1, in
print t.__used_names
AttributeError: test instance has no attribute '__used_names'
>>> print t._test__used_names
['name1', 'name2']

没有评论: