web-dev-qa-db-ja.com

なぜPythonでオブジェクトに属性を追加できないのですか?

(Python Shell)で記述されています)

>>> o = object()
>>> o.test = 1

Traceback (most recent call last):
  File "<pyshell#45>", line 1, in <module>
    o.test = 1
AttributeError: 'object' object has no attribute 'test'
>>> class test1:
    pass

>>> t = test1()
>>> t.test

Traceback (most recent call last):
  File "<pyshell#50>", line 1, in <module>
    t.test
AttributeError: test1 instance has no attribute 'test'
>>> t.test = 1
>>> t.test
1
>>> class test2(object):
    pass

>>> t = test2()
>>> t.test = 1
>>> t.test
1
>>> 

オブジェクトが属性を追加できないのはなぜですか?

60
quano

objectインスタンスには__dict__属性がないことに注意してください。

>>> dir(object())
['__class__', '__delattr__', '__doc__', '__getattribute__', '__hash__', '__init__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__str__']

派生クラスでこの動作を説明する例:

>>> class Foo(object):
...     __slots__ = {}
...
>>> f = Foo()
>>> f.bar = 42
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'Foo' object has no attribute 'bar'

slots のドキュメントから引用:

[...] __slots__宣言は、インスタンス変数のシーケンスを受け取り、各インスタンスに十分なスペースを確保して、各変数の値を保持します。 __dict__はインスタンスごとに作成されないため、スペースが節約されます。

編集:コメントからThomasHに答えるために、OPのテストクラスは「古いスタイル」のクラスです。試してください:

>>> class test: pass
...
>>> getattr(test(), '__dict__')
{}
>>> getattr(object(), '__dict__')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'object' object has no attribute '__dict__'

__dict__インスタンスがあることに気付くでしょう。オブジェクトクラスには__slots__が定義されていない場合がありますが、結果は同じです。__dict__がないため、属性の動的な割り当てができません。これを明確にするために回答を再編成しました(2番目の段落を先頭に移動します)。

45
ars

良い質問です。私の推測では、object組み込み/拡張タイプであるという事実に関係しているということです。

_>>> class test(object):
...  pass
...
>>> test.test = 1
>>> object.test = 1
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: can't set attributes of built-in/extension type 'object'
_

IIRC、これは___dict___属性の存在、またはより正確には、オブジェクトが___dict___属性を持たないときにsetattr()爆発することに関係しています。

3
D.Shawley