无法将属性设置为字符串吗?

9 投票
2 回答
868 浏览
提问于 2025-04-17 05:04

通常情况下,你可以给自定义对象设置任意属性,比如:

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

但是,你不能对字符串对象做同样的操作:

----------
>>> 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__'
>>>
----------

为什么呢?

2 个回答

2

http://docs.python.org/reference/datamodel.html

如果一个类里面有 setattr() 或 delattr() 这两个方法,那么在更新这个类的实例字典时,就会调用这两个方法,而不是直接修改字典。

http://docs.python.org/reference/datamodel.html#object.setattr

11

因为 str 类型是一个没有字典属性的类型。从文档的“类”部分可以看到:

一个类有一个由字典对象实现的命名空间。类属性的引用会被转换成在这个字典中的查找,比如 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 版本有关。

撰写回答