だから、私は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オブジェクトに属性を割り当てることができないと指定されていますか?
任意の属性の割り当てをサポートするには、オブジェクトに__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
...だけでfoobar
sが必要な場合はどうでしょうか?まれな必要性ですが、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つの参照を保持できる場所)を装備する与えられた名前で。
失われた柔軟性と引き換えに、インスタンスごとに多くのバイトを獲得します(おそらく、何十億ものインスタンスが駆け巡っている場合にのみ意味がありますが、 /のユースケースがあります)。
他の回答者が言ったように、object
には__dict__
。 object
は、int
またはstr
を含むall型の基本クラスです。したがって、object
によって提供されるものはすべて、彼らにとっても負担になります。 オプション__dict__
は、値ごとに追加のポインタが必要になります。これは、非常に限られたユーティリティのために、システム内の各オブジェクトに対して追加の4〜8バイトのメモリを無駄にします。
Python 3.3+では、ダミークラスのインスタンスを実行する代わりに、 types.SimpleNamespace
このため。
それは単に最適化によるものです。
口述は比較的大きい。
>>> import sys
>>> sys.getsizeof((lambda:1).__dict__)
140
Cで定義されているほとんど(おそらくすべて)のクラスには、最適化のためのディクテーションがありません。
ソースコード を見ると、オブジェクトにdictがあるかどうかを確認する多くのチェックがあることがわかります。
だから、私自身の質問を調査して、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」のような「オブジェクト」を考えるとき、これは今や私には理にかなっていると思います。
これは、オブジェクトがクラスではなく「タイプ」であるためです。一般に、Cの拡張機能で定義されているすべてのクラス(組み込みのすべてのデータ型、およびnumpy配列など)では、任意の属性を追加できません。