259

属性呼び出しによって内部の辞書にアクセスできるようにする必要がある独自のコンテナーを作成しています。コンテナーの一般的な使用法は次のようになります。

dict_container = DictContainer()
dict_container['foo'] = bar
...
print dict_container.foo

このようなことを書くのはばかげているかもしれませんが、それが私が提供する必要がある機能です。これを次の方法で実装することを考えていました。

def __getattribute__(self, item):
    try:
        return object.__getattribute__(item)
    except AttributeError:
        try:
            return self.dict[item]
        except KeyError:
            print "The object doesn't have such attribute"

ネストされた try/except ブロックが適切な方法かどうかはわかりません。そのため、別の方法として and を使用hasattr()has_key()ます。

def __getattribute__(self, item):
        if hasattr(self, item):
            return object.__getattribute__(item)
        else:
            if self.dict.has_key(item):
                return self.dict[item]
            else:
                raise AttributeError("some customised error")

または、それらの 1 つと 1 つの try catch ブロックを次のように使用します。

def __getattribute__(self, item):
    if hasattr(self, item):
        return object.__getattribute__(item)
    else:
        try:
            return self.dict[item]
        except KeyError:
            raise AttributeError("some customised error")

最も Pythonic でエレガントなオプションはどれですか?

4

11 に答える 11

230

最初の例はまったく問題ありません。Python の公式ドキュメントでさえ、EAFPとして知られるこのスタイルを推奨しています。

個人的には、必要でない場合はネストを避けることを好みます。

def __getattribute__(self, item):
    try:
        return object.__getattribute__(item)
    except AttributeError:
        pass  # Fallback to dict
    try:
        return self.dict[item]
    except KeyError:
        raise AttributeError("The object doesn't have such attribute") from None

PS。has_key()は Python 2 で長い間廃止されてきましたitem in self.dict。代わりに使用してください。

于 2013-06-09T23:46:45.417 に答える
23

Java では、フロー制御に例外を使用することは確かに悪い習慣ですが (主に、例外によって JVM がリソースを収集するように強制されるためです (詳細はこちら))、Python では、ダック タイピングEAFPという 2 つの重要な原則があります。これは基本的に、オブジェクトが機能すると思う方法でオブジェクトを使用してみて、そうでない場合に対処することをお勧めすることを意味します。

要約すると、唯一の問題は、コードがインデントされすぎることです。必要に応じて、上記の提案された回答で提案されているlqcのように、ネストの一部を単純化してみてください。

于 2013-06-09T23:46:11.913 に答える
13

特定の例では、実際にネストする必要はありません。ブロック内の式がtry成功すると、関数が返されるため、try/except ブロック全体の後のコードは、最初の試行が失敗した場合にのみ実行されます。したがって、次のことができます。

def __getattribute__(self, item):
    try:
        return object.__getattribute__(item)
    except AttributeError:
        pass
    # execution only reaches here when try block raised AttributeError
    try:
        return self.dict[item]
    except KeyError:
        print "The object doesn't have such attribute"

それらをネストすることは悪くありませんが、フラットのままにしておくと、構造がより明確になるように感じます。一連のことを順番に試して、最初に機能するものを返します。

__getattribute__ちなみに、ここの代わりに本当に使いたいのか考えた方がいいかもしれません__getattr__。を使用__getattr__すると、通常の属性ルックアップ プロセスが既に失敗していることがわかるため、作業が簡素化されます。

于 2013-06-09T23:45:59.897 に答える
8

私の意見では、これはそれを処理するための最もPythonicな方法ですが、それはあなたの質問を無意味にするからです。__getattr__()これはの代わりに を定義することに注意してください。これは__getattribute__() 、内部ディクショナリに保持されている「特別な」属性のみを処理する必要があることを意味するためです。

def __getattr__(self, name):
    ''' Only called when an attribute lookup in the "usual" places has failed. '''
    try:
        return self.my_dict[name]
    except KeyError:
        raise AttributeError("some customized error message")
于 2013-06-09T23:52:16.217 に答える
5

Python では、許可よりも許しを求める方が簡単です。入れ子になった例外処理を気にしないでください。

(さらに、has*とにかく、ほとんどの場合、カバーの下で例外を使用します。)

于 2013-06-09T23:40:37.497 に答える
3

古い例外を処理しているときに、新しい例外が発生するのを避けたいと思っています。エラーメッセージが読みにくくなります。

たとえば、私のコードでは、最初に書いた

try:
    return tuple.__getitem__(self, i)(key)
except IndexError:
    raise KeyError(key)

そして、私はこのメッセージを受け取りました。

>>> During handling of above exception, another exception occurred.

私はこれが欲しかった:

try:
    return tuple.__getitem__(self, i)(key)
except IndexError:
    pass
raise KeyError(key)

例外の処理方法には影響しません。どちらのコード ブロックでも、KeyError がキャッチされます。これは単にスタイル ポイントの取得の問題です。

于 2015-02-02T15:04:57.607 に答える
0

Pythonic であることやエレガントであることは問題ではないと思います。できる限り例外を防ぐことが問題です。例外は、制御できないコードまたはイベントで発生する可能性のあるエラーを処理するためのものです。

この場合、アイテムが属性であるか辞書であるかをチェックするときに完全に制御できるため、ネストされた例外を避け、2 回目の試行に固執してください。

于 2013-06-09T23:49:30.577 に答える