2016-10-04 12 views
2

objectから(暗黙的に)派生するクラスには、明示的な基本クラスを持つクラスよりも多くのアイテムが__dict__に含まれているのはなぜですか? (Python 3.5)。明示的な基底クラスを持つクラスと持たないクラスの間の__dict__の相違点

class X: 
    pass 
class Y(X): 
    pass 
X.__dict__ 
''' 
mappingproxy({'__dict__': <attribute '__dict__' of 'X' objects>, 
       '__doc__': None, 
       '__module__': '__main__', 
       '__weakref__': <attribute '__weakref__' of 'X' objects>}) 
''' 

Y.__dict__ 
''' 
mappingproxy({'__doc__': None, '__module__': '__main__'}) 
''' 

答えて

3

__weakref____dict__の定義は、その適切な記述は、Pythonレベルのコードは、それを探したときに弱参照リストの「本物」の場所とクラスのインスタンスのインスタンス辞書にアクセスするために呼び出されています。基底クラスobjectは無骨であり、__weakref__または__dict__weakref.ref(object())が失敗するようにsetattr(object(), 'foo', 0))のスペースを予約しません。

ユーザ定義クラスの場合、これらの値を見つけるための記述子を定義する必要があります(CPythonでは、Cレイヤに直接ポインタがあるため、これらのアクセサは通常バイパスされますが、instance.__dict__を明示的に参照する場合、インスタンスのクラスを通してそれを見つける方法を知っている)。 objectの最初の子(__slots__なし)は、これらの記述子を定義する必要があります。サブクラスは、__dict____weakref__の位置が変更されないため、必要ありません。それらのインスタンスは同じ相対的なオフセットでそれらの属性を持つため、引き続き基本クラスのアクセサーを使用できます。

基本的に、第一の非__slot__ -edユーザ定義クラスがフォームのC構造体としてインスタンスの考えを作成している:

struct InstanceObject { 
    ... common object stuff ... 
    ... anything defined by __slots__ in super class(es), if anything ... 
    PyObject *location_of___dict__; 
    PyObject *location_of___weakref__; 
} 

とアクセサを決定するために、型を確認するために実装されています構造体メンバのlocation*のオフセットを取得してからそれらを取得します。子クラスのstruct定義では、location*メンバーのオフセットは変更されません(新規の場合は__slots__が追加され、追加されたばかりです)ので、親から同じアクセサを再利用できます。

+0

注:これはすべてCPythonの実装の詳細であり、いつでも変更される可能性があります。彼らが望むのであれば、 '__dict__'と' __weakref__'のアクセサをサブクラスにコピーして、 '__dict__' /' __weakref__'が直接アクセスされたときに追加のルックアップを節約することができますが、(注記したように)CPythonはアクセサコードはそれらを直接アクセスします(CレベルのものはPython可視アクセッサをバイパスします)。そのような最適化(おそらく各クラス定義のためのより多くのメモリを犠牲にして)はおそらく価値がないと考えられます。 – ShadowRanger

関連する問題