12

次のような抽象基本クラスを持つ例外クラスがあるとします。

class MyExceptions(BaseExeption, metaclass=abc.ABCMeta):
    pass

class ProperSubclass(MyExceptions):
    pass

MyExceptions.register(ValueError)

ProperSubclassでキャッチできるようですが、ではキャッチできMyExceptionsませんValueError

try:
    raise ProperSubclass()
except MyExceptions:
    print('As expected, control comes here...')
except:
    print('...and not here.')

try:
    raise ValueError()
except MyExceptions:
    print('Control does not come here...')
except ValueError:
    print('...but unexpectedly comes here.')

私の質問は、組み込み例外を抽象基本クラスでキャッチできるようにする必要があるかどうかです。もしそうなら、どのように?そうでない場合、ルールは何ですか?

これを尋ねる別の方法は次のとおりだと思います: 節を除いて isinstance()/issubclass() を適切に使用してマッチングを行いますか?そうでない場合(そうであるように)、何使用しますか? おそらく、C の実装には怪しげなショートカットがいくつかあるでしょう。

4

1 に答える 1

15

ドキュメントには次のように記載されています。

オブジェクトが例外オブジェクトのクラスまたは基底クラスである場合、または例外と互換性のあるアイテムを含むタプルである場合、オブジェクトは例外と互換性があります。

残念ながら、これはissubclass などの言語とは異なり、仮想基底クラスを考慮する必要があるかどうかを示していません。

classがclassinfoのサブクラス (直接、間接、または仮想) である場合に true を返します。[...]

インスタンスとサブクラスのチェックをオーバーライドする言語もあまり役に立ちません。

isinstance()次のメソッドは、およびissubclass()組み込み関数のデフォルトの動作をオーバーライドするために使用されます。[...]

実際、ご想像のとおり、CPython 実装 (Python 3 用) はサブクラス チェックをバイパスし、次のコードをPyType_IsSubtype直接呼び出します。

http://hg.python.org/cpython/file/3.4/Python/errors.c#l167

PyErr_GivenExceptionMatches(PyObject *err, PyObject *exc)
{
    ...
        /* PyObject_IsSubclass() can recurse and therefore is
           not safe (see test_bad_getattr in test.pickletester). */
        res = PyType_IsSubtype((PyTypeObject *)err, (PyTypeObject *)exc);

参考までに、 issubclass の CPython 実装であるPyObject_IsSubclass__subclasscheck__は、にフォールバックする前に呼び出しますPyType_IsSubtype

したがって、この動作には十分な理由があります。例外処理は非再帰的である必要があるため、Python コードに戻すのは安全ではありません。Python 2.7 バージョンは、オーバーフローのリスクを受け入れ、 を呼び出すことに注意してくださいPyObject_IsSubclassPython 3 でこの制限を緩和する提案がありますが、パッチが作成されていますが、まだ受け入れられていません。exceptそれ以外の場合は、ドキュメントでチェックが非仮想であることを明確にすることをお勧めします。

于 2014-05-27T14:14:05.837 に答える