36

Pythonクラスで、クラスの他の属性のいくつかをそのメソッドを実行する前に変更する必要がある場合、インスタンスメソッドからどのような種類のエラーを発生させる必要がありますか?

「メソッド呼び出しがオブジェクトの現在の状態に対して無効な場合にスローされる例外」を使用するC#のバックグラウンドから来ていますが、PythonでInvalidOperationException同等の組み込み例外を見つけることができませんでした。

問題が関数パラメーターにある場合、私は提起していましたValueError(「組み込みの操作または関数が正しい型であるが不適切な値の引数を受け取ったときに提起されました」)。これは技術的にはselfパラメータの無効な値だと思います。それはそれを扱う正しい方法ですか?たとえば、これは慣用的なものですraise ValueError("self.foo must be set before running self.bar()")か?

4

6 に答える 6

35

ValueErrorこの場合、上げるのが最善です。Python の場合、独自の例外タイプを作成するよりも、組み込みの例外タイプを使用することをお勧めします。新しい例外の型を作成するのは、それをキャッチする必要があり、組み込みの型をキャッチするときとは大きく異なる動作をする必要があると予想される場合に限ってください。この場合、このような状況は発生しないはずです。問題のクラスを使用する際のエラーを示しているため、これをキャッチすることは想定していません。このため、別の名前を付けるためだけに新しい型を作成する価値はありません。これが、渡すメッセージ文字列のValueError()目的です。

このような無効な状態が発生しないようにクラスを再構築することは可能ですか?

于 2012-05-23T20:39:34.310 に答える
14

RuntimeErrorすべての組み込み例外の中で、無効な状態を通知するのに最も適していると思います。

CPython での使用方法のこの例を参照してください。

Python 2.7.10 (default, Jul 13 2015, 12:05:58)
[GCC 4.2.1 Compatible Apple LLVM 6.1.0 (clang-602.0.53)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> from threading import Thread
>>> Thread().join()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/local/Cellar/python/2.7.10_2/Frameworks/Python.framework/Versions/2.7/lib/python2.7/threading.py", line 938, in join
    raise RuntimeError("cannot join thread before it is started")
RuntimeError: cannot join thread before it is started

CPython の実装自体でさえ、ライブラリ間の特定の例外タイプの使用について一貫性がないことに注意することが重要です。代わりに が使用されることもありValueErrorますが、私の意見では、Python ドキュメントからのその説明は、その使用が他の状況のた​​めに予約されていることを示しています。RuntimeErrorはより一般的な例外であり、適切な入力が与えられた場合でもコードの一部が正しく動作しない場合に使用する必要があります。これは、オブジェクトが無効な状態にある場合と似ています。

于 2015-09-04T12:40:33.687 に答える
2
class InvalidOperationException(Exception):
    pass

SYS_STATE = 1

def something_being_run():
    if SYS_STATE < 2:
        raise InvalidOperationException

そのようなことを意味しますか?独自の例外タイプを作成するために例外をサブクラス化してはならない理由はわかりませんが、それは私の古い Oracle PL/SQL Dev が出てくるだけかもしれません...

于 2012-05-23T20:12:36.480 に答える
2

Pythonic の方法は、エラー状態にあるにもかかわらず、メソッド呼び出しがクラッシュしないような状態でオブジェクトを放置しないことだと思います。プログラムが最終的に倒れるポイントはバグが発生した場所ではないため、これらは見つけるのが最も難しいバグです。

例えば。

class PseudoTuple(object):
    """
The sum method of PseudoTuple will raise an AttributeError if either x or y have
not been set
"""
    def setX(self, x):
        self.x = x

    def setY(self, y):
        self.y = y

    def sum(self):
        """
In the documentation it should be made clear that x and y need to have been set
for sum to work properly
"""
        return self.x + self.y

class AnotherPseudoTuple(PseudoTuple):
     """
For AnotherPseudoTuple sum will now raise a TypeError if x and y have not been 
properly set
"""
    def __init__(self, x=None, y=None):   
        self.x = x
        self.y = y

してはいけないことは次のようなものです

class BadPseudoTuple(PseudoTuple):
    """
In BadPseudoTuple -1 is used to indicate an invalid state
"""
    def __init__(self, x=-1, y=-1):
        self.x = x
        self.y = y

    def sum(self):
        if self.x == -1 or self.y == -1:
            raise SomeException("BadPseudoTuple in invalid state")
        else:
            return self.x + self.y

これは、次のpythonicのモットーに基づいていると思います。

許可を得るより許しを請うほうが簡単だ

例外的な状態が、クラスの誤用によるユーザー エラーではなく、通常の実行過程で発生することが予想されるものである場合は、独自の例外を作成する必要があると思われます。StopIteration と反復子は、この例です。

于 2012-05-23T20:46:10.147 に答える
1

ValueErrorAssertionError私には大丈夫ですが、より適切だと思います。基本的に、API 設計者の主張に違反しています。

于 2013-04-28T03:04:18.053 に答える
-1

ValueErrorあなたがやっているように、問題が関数パラメータにあるAttributeErrorとき、および問題が設定しなければならない属性にあるときは、あなたが提起すべきだと思います。

また、より具体的な例外を作成するためにサブクラス化することもできますが、AttributeError必要ではないと思います。エラーメッセージのAttributeError例外は十分に明確です。

于 2012-05-23T20:49:36.463 に答える