2011-10-27 32 views
8

通常情况下,你可以设置为自定义对象的任意属性,例如不可能将属性设置为字符串?

---------- 
>>> a=A() 
>>> a.foo=42 
>>> a.__dict__ 
{'foo': 42} 
>>> 
---------- 

在另一方面,你可以做不一样的约束力和String对象:

---------- 
>>> a=str("bar") 
>>> a.foo=42 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
AttributeError: 'str' object has no attribute 'foo' 
>>> a.__dict__ 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
AttributeError: 'str' object has no attribute '__dict__' 
>>> 
---------- 

为什么?

回答

9

因为str类型是一种没有属性字典的类型。从the docs,“类”部分:

类有一个由字典对象实现的名称空间。 类属性引用被翻译成查找这个 词典,例如,C.x转换为C.__dict__["x"]

您也可以执行类似的自定义对象:

>>> class X(object): 
...  __slots__=('a',) 
... 
>>> a = X() 
>>> a.a = 2 
>>> a.foo = 2 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
AttributeError: 'X' object has no attribute 'foo' 

一般情况下,你不应该设置或修改你不应该的对象的字段。具体数据类型的文档应该引用您可用于公开修改的字段。

例如,ReadOnlyPoint对象,其中,x和y坐标仅在对象构造设置:

>>> class ReadOnlyPoint(object): 
...  __slots__ = ('_x', '_y') 
...  def __init__(self, x, y): 
...    self._x = x 
...    self._y = y 
...  def getx(self): 
...    return self._x 
...  def gety(self): 
...    return self._y 
...  x = property(getx) 
...  y = property(gety) 
... 
>>> p = ReadOnlyPoint(2, 3) 
>>> print p.x, p.y 
2 3 
>>> p.x = 9 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
AttributeError: can't set attribute 
>>> p._x = 9 
>>> print p.x, p.y 
9 3 

虽然xy属性是只读的,访问对象的内部允许你改变对象的状态。

将可吸入性添加到str对象的新字段是实现细节,特定于您正在使用的Python版本。

+0

是不是那'str'类型基本上被设计为不可改变的事实的结果?如果你从'str'继承创建一个类(在我的例子中是空类),你将不会得到上述错误。但是对于元组,你会得到这个错误(它们也是不可变的)。 – Tadeck

+0

@Tadeck好吧,这两个原因真正起作用 - string是内置的,没有'__dict__',就像'__slots__'模块[边界情况](http://docs.python)的用户定义类一样。组织/ py3k /参考/ datamodel.html#笔记-上使用时隙)。无论如何,它也不会支持属性赋值,因为字符串是不可变的。这也可以在OP的第二个错误消息中看到(“str对象没有属性__dict__”)。 – delnan

+4

@Tadeck它与可变性无关。试着用'list',你会得到相同的结果。你不能做到任何基本的内置类型 – agf