web-dev-qa-db-ja.com

オブジェクトクラスの属性を設定できません

だから、私はPythonに答えている間 この質問 で遊んでいましたが、これが無効であることを発見しました:

o = object()
o.attr = 'hello'

AttributeError: 'object' object has no attribute 'attr'。ただし、オブジェクトから継承したクラスでは有効です。

class Sub(object):
    pass

s = Sub()
s.attr = 'hello'

印刷s.attrは、期待どおり 'hello'を表示します。これはなぜですか? Python言語仕様では、Vanillaオブジェクトに属性を割り当てることができないと指定されていますか?

83
Smashery

任意の属性の割り当てをサポートするには、オブジェクトに__dict__:オブジェクトに関連付けられた辞書が必要です。ここに任意の属性を格納できます。それ以外の場合、 put 新しい属性を配置する場所がありません。

objectのインスタンスは__dict__持ちませんします-持っている場合、恐ろしい循環依存問題の前に(ほとんどのようなdictから)それ以外はすべて、object ;-)から継承します。これにより、 every Python内のオブジェクトにdictが追加され、オーバーヘッドがになります。現在、dictを持たないか、必要としないオブジェクトごとの多くのバイト(本質的に、任意に割り当て可能な属性を持たないすべてのオブジェクトは、dictを持たない、または必要としない)。

たとえば、優れたpymplerプロジェクト(svnから here から取得できます)を使用すると、いくつかの測定を行うことができます...:

>>> from pympler import asizeof
>>> asizeof.asizeof({})
144
>>> asizeof.asizeof(23)
16

すべてのintが16バイトではなく144バイトを使用することを望まないでしょうか?

今、あなたがクラスを作るとき(何からでも継承する)、物事は変わります...:

>>> class dint(int): pass
... 
>>> asizeof.asizeof(dint(23))
184

...__dict__ is が追加されました(さらに、オーバーヘッドが少し増えます)-dintインスタンスは任意の属性を持つことができますが、その柔軟性。

では、 one 追加属性int...だけでfoobarsが必要な場合はどうでしょうか?まれな必要性ですが、Pythonはそのための特別なメカニズムを提供します...

>>> class fint(int):
...   __slots__ = 'foobar',
...   def __init__(self, x): self.foobar=x+100
... 
>>> asizeof.asizeof(fint(23))
80

... quite intほど小さくありません。 (または2つのint、1つはself、もう1つはself.foobar-2つ目は再割り当て可能)ですが、dintよりもはるかに優れています。

クラスに__slots__特殊属性(文字列のシーケンス)がある場合、classステートメント(より正確には、デフォルトのメタクラス、type)はnotそのクラスのすべてのインスタンスに__dict__(したがって、任意の属性を持つ機能)、有限の「スロット」の厳密なセット(基本的に、それぞれがいくつかのオブジェクトへの1つの参照を保持できる場所)を装備する与えられた名前で。

失われた柔軟性と引き換えに、インスタンスごとに多くのバイトを獲得します(おそらく、何十億ものインスタンスが駆け巡っている場合にのみ意味がありますが、 /のユースケースがあります)。

125
Alex Martelli

他の回答者が言ったように、objectには__dict__objectは、intまたはstrを含むall型の基本クラスです。したがって、objectによって提供されるものはすべて、彼らにとっても負担になります。 オプション__dict__は、値ごとに追加のポインタが必要になります。これは、非常に限られたユーティリティのために、システム内の各オブジェクトに対して追加の4〜8バイトのメモリを無駄にします。


Python 3.3+では、ダミークラスのインスタンスを実行する代わりに、 types.SimpleNamespace このため。

17
Antti Haapala

それは単に最適化によるものです。

口述は比較的大きい。

>>> import sys
>>> sys.getsizeof((lambda:1).__dict__)
140

Cで定義されているほとんど(おそらくすべて)のクラスには、最適化のためのディクテーションがありません。

ソースコード を見ると、オブジェクトにdictがあるかどうかを確認する多くのチェックがあることがわかります。

4
Unknown

だから、私自身の質問を調査して、Python言語:あなたはintのようなものから継承することができ、同じ動作を見ることができます。

>>> class MyInt(int):
       pass

>>> x = MyInt()
>>> print x
0
>>> x.hello = 4
>>> print x.hello
4
>>> x = x + 1
>>> print x
1
>>> print x.hello
Traceback (most recent call last):
  File "<interactive input>", line 1, in <module>
AttributeError: 'int' object has no attribute 'hello'

最後のエラーは、add関数がintを返すためだと思います。カスタム属性を保持するには、__add__などの関数をオーバーライドする必要があります。しかし、「int」のような「オブジェクト」を考えるとき、これは今や私には理にかなっていると思います。

1
Smashery

これは、オブジェクトがクラスではなく「タイプ」であるためです。一般に、Cの拡張機能で定義されているすべてのクラス(組み込みのすべてのデータ型、およびnumpy配列など)では、任意の属性を追加できません。

0
Ryan