私は、MongoDB と呼ばれる単純なデータベース層( minimongoに触発された) の作成者であり、現在、複数のプロジェクトにいる場合はほぼ間違いなく唯一のユーザーkale
です。モデルの基本クラスでの現在の使用は__getattr__
、追跡が困難なバグにつながりました。
私が遭遇した問題は、昨年 6 月に David Halterによってこのサイトで簡潔に説明されました。議論は興味深いですが、解決策は提供されませんでした。
要するに:
>>> class A(object):
... @property
... def a(self):
... print "We're here -> attribute lookup found 'a' in one of the usual places!"
... raise AttributeError
... return "a"
...
... def __getattr__(self, name):
... print "We're here -> attribute lookup has not found the attribute in the usual places!"
... print('attr: ', name)
... return "not a"
...
>>> print(A().a)
We're here -> attribute lookup found 'a' in one of the usual places!
We're here -> attribute lookup has not found the attribute in the usual places!
('attr: ', 'a')
not a
>>>
この矛盾した動作は、公式の python ドキュメントを読んで期待するものではないことに注意してください。
object.__getattr__(self, name)
属性ルックアップが通常の場所で属性を見つけられなかった場合に呼び出されます (つまり、インスタンス属性ではなく、self のクラス ツリーにも見つかりません)。name は属性名です。
AttributeError
(属性が「通常の場所」で見つかったかどうかを「属性ルックアップ」が知る手段であると彼らが言及してくれればうれしいです。明確にするための括弧はせいぜい不完全に思えます。)
@property
実際には、記述子の Thing で AttributeError が発生した場合、プログラミング エラーによって引き起こされたバグを追跡する際に問題が発生しました。
>>> class MessedAttrMesser(object):
... things = {
... 'one': 0,
... 'two': 1,
... }
...
... def __getattr__(self, attr):
... try:
... return self.things[attr]
... except KeyError as e:
... raise AttributeError(e)
...
... @property
... def get_thing_three(self):
... return self.three
...
>>>
>>> blah = MessedAttrMesser()
>>> print(blah.one)
0
>>> print(blah.two)
1
>>> print(blah.get_thing_three)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 11, in __getattr__
AttributeError: 'get_thing_three'
>>>
この場合、クラス全体を検査することで、何が起こっているかは明らかです。ただし、スタック トレースからのメッセージ に依存している場合AttributeError: 'get_thing_three'
は意味がありませんget_thing_three
。
の目的は、kale
モデルを構築するための基本クラスを提供することです。そのため、ベース モデル コードはエンド プログラマから隠され、このようなエラーの原因を隠すことは理想的ではありません。
末端のプログラマー (せっかく@property
) は、モデルに記述子を使用することを選択する場合があり、そのコードは期待どおりに機能し、失敗するはずです。
質問
AttributeError
を定義した基本クラスを介して s を伝播させるにはどうすればよい__getattr__
ですか?