Python 2.6で廃止されたBaseException.message


177

次のユーザー定義の例外を使用すると、Python 2.6ではBaseException.messageが廃止されるという警告が表示されます。

class MyException(Exception):

    def __init__(self, message):
        self.message = message

    def __str__(self):
        return repr(self.message)

これは警告です:

DeprecationWarning: BaseException.message has been deprecated as of Python 2.6
self.message = message

これの何が問題になっていますか?非推奨の警告を取り除くには何を変更する必要がありますか?


9
理由については、PEP 352を参照してください:python.org/dev/peps/pep-0352/#retracted-ideas
balpha

回答:


154

解決策-コーディングはほとんど必要ありません

例外クラスを継承Exceptionし、最初のパラメーターとしてメッセージをコンストラクターに渡すだけです。

例:

class MyException(Exception):
    """My documentation"""

try:
    raise MyException('my detailed description')
except MyException as my:
    print my # outputs 'my detailed description'

あなたは使用することができますstr(my)か(以下、エレガントな)my.args[0]カスタムメッセージにアクセスすること。

バックグラウンド

新しいバージョンのPython(2.6以降)では、カスタム例外クラスを(Python 2.5以降)BaseExceptionから継承するExceptionから継承することになっています。背景については、PEP 352で詳しく説明されています。

class BaseException(object):

    """Superclass representing the base of the exception hierarchy.
    Provides an 'args' attribute that contains all arguments passed
    to the constructor.  Suggested practice, though, is that only a
    single string argument be passed to the constructor."""

__str__そして__repr__既に特に(メッセージとして使用することができる)一方のみ引数の場合について、有意義な方法で実装されています。

他の人が提案するように、繰り返し__str____init__実装、または作成する必要はありません_get_message


5
@Mattによって提案されたBaseExceptionをExceptionに変更
geekQ

8
str例外がユニコード引数で作成された場合のブレークの使用:str(MyException(u'\xe5'))raises UnicodeEncodeError。のunicode代わりにを使用してstrも、unicode(MyException('\xe5'))UnicodeDecodeErrorが発生するため、絶対確実ではありません。これは、引数がstrまたはであるかどうか事前にわからない場合、以前使用していた場所をunicode使用する必要.args[0]があることを意味し.messageますか?
kasperd 2014

1
@kasperdほとんどすべてのPythonユニコードの問題と同様に、これはユニコードサンドイッチで解決できます。
Ryan P 14

3
@RyanPこれは、私が実際に何が行われるかを制御できることを前提としています。これが私が直面した人生の事実です。複数のサードパーティライブラリからの例外を処理する必要があります。それらのいくつかは例外にユニコードを渡し、いくつかはstrを渡します。ライブラリの1つには、Unicodeから継承する独自のクラスがありますが、独自のreprメソッドがあります。これは、仕様で要求されるstrではなく、Unicodeを返します。
kasperd 2014

1
ところで。.messageプロジェクト内ののすべての使用をに置き換えます.args[0]。これで問題は発生していません。
kasperd 2014

26

はい、Python 3.0では廃止されるため、Python 2.6では廃止されました。

BaseExceptionクラスは、エラーメッセージを格納する方法を提供しなくなりました。自分で実装する必要があります。メッセージを格納するためのプロパティを使用するサブクラスでこれを行うことができます。

class MyException(Exception):
    def _get_message(self): 
        return self._message
    def _set_message(self, message): 
        self._message = message
    message = property(_get_message, _set_message)

お役に立てれば


1
昇給中にメッセージをどのように初期化しますか?彼のコードは、MyException( "some message")を呼び出すことによってメッセージが設定されることを示しました
eric.frederich

私の例のメソッドは、メッセージプロパティを実装するためだけのものです。プロパティの使用方法はコーダー次第です。この場合、OPはコードに投稿したinitおよびstrメソッドを使用します。
Sahaは2010

1
別の変数を読み取るだけの場合は、getter / setterではなくpublic変数の使用を検討してください。@propertyカプセル化が本当に必要な場合は、いつでも構文にアップグレードできます。
vdboor 2012年

2
@vdboor:彼@propertyは非推奨の警告を無効にするために使用しています。
bukzor

値を取得および設定するだけで、チェックされていない変更されていないプロパティを作成することは、Pythonを使用していないため役に立たない。プロパティの重要な点は、ゲッターやセッターが実際に必要になるまで、パブリック属性を自由に使用できるようにすることです。次に、クライアントコードを壊すことなく、public属性をプロパティに変換します。
Luciano Ramalho

9
class MyException(Exception):

    def __str__(self):
        return repr(self.args[0])

e = MyException('asdf')
print e

これはPython2.6スタイルのクラスです。新しい例外は、任意の数の引数を取ります。


1
古いExceptionクラスも任意の数の引数を取ります。行っているようなメッセージプロパティを完全に回避できますが、既存のコードが壊れる場合は、独自のメッセージプロパティを実装することで問題を解決できます。
Sahas

8

警告を複製する方法

問題を明確にしましょう。質問のサンプルコードではこれを複製できないため、警告がオンになっている場合(-WフラグPYTHONWARNINGS環境変数、または警告モジュールを介して)、Python 2.6および2.7で警告が複製されます

>>> error = Exception('foobarbaz')
>>> error.message
__main__:1: DeprecationWarning: BaseException.message has been deprecated as of Python 2.6
'foobarbaz'

使用をやめる .message

私が好むrepr(error)ものがある場合は、エラーの種類の名前、メッセージののreprを含む文字列、および残りの引数ののreprを返します。

>>> repr(error)
"Exception('foobarbaz',)"

使用中の警告の排除 .message

そして、あなたが得る方法取り除くのは、DeprecationWarningPythonの設計者が意図したとおりに組み込み例外をサブクラス化することです。

class MyException(Exception):

    def __init__(self, message, *args):
        self.message = message
        # delegate the rest of initialization to parent
        super(MyException, self).__init__(message, *args)

>>> myexception = MyException('my message')
>>> myexception.message
'my message'
>>> str(myexception)
'my message'
>>> repr(myexception)
"MyException('my message',)"

.messageなしで属性のみを取得するerror.message

例外に対する1つの引数(メッセージ)があり、それが必要なことがわかっている場合は、メッセージ属性を回避しstr、エラーを取得することをお勧めします。サブクラス化のために言うException

class MyException(Exception):
    '''demo straight subclass'''

そして使い方:

>>> myexception = MyException('my message')
>>> str(myexception)
'my message'

この回答もご覧ください:

最新のPythonでカスタム例外を宣言する適切な方法は?


4

私の知る限り、メッセージ属性に別の名前を使用するだけで、基本クラスとの競合が回避され、非推奨の警告が停止します。

class MyException(Exception):

def __init__(self, message):
    self.msg = message

def __str__(self):
    return repr(self.msg)

私にはハックのようです。

サブクラスがメッセージ属性を明示的に定義している場合でも、警告が発行される理由を誰かが説明できるかもしれません。基本クラスにこの属性がなくなった場合、問題はありません。


4

geekQの回答から続けて、推奨されるコード置換は、何をする必要があるかによって異なります。

### Problem
class MyException(Exception):
    """My documentation"""

try:
    raise MyException('my detailed description')
except MyException as my:
    ### Solution 1, fails in Python 2.x if MyException contains 🔥
    # with UnicodeEncodeError: 'ascii' codec can't encode characters in position 24-25: ordinal not in range(128)
    print(my)  # outputs 'my detailed description'

### Solution 2
# Works in Python 2.x if exception only has ASCII characters,
# should always work in Python 3.x
str(my)

### Solution 3
# Required in Python 2.x if you need to handle non-ASCII characters,
# such as δσφφδσ (as pointed out by jjc) or emoji 🔥 💕 🎁 💯 🌹
# but does not work in Python 3.x
unicode(my)

例外には複数の引数がある場合があるため、 my.args[0]、すべての関連情報が提供されるとは限りません。

例えば:

# Python 2.7
try:
    u'\u12345'.encode('utf-8').encode('utf-8')
except UnicodeDecodeError as e:
    print e.args[0]
    print e.args
    print str(e)

出力として印刷:

ascii
('ascii', '\xe1\x88\xb45', 0, 1, 'ordinal not in range(128)')
'ascii' codec can't decode byte 0xe1 in position 0: ordinal not in range(128)

ただし、たとえば次の理由により、状況依存のトレードオフです。

# Python 2.7
>>> str(SyntaxError())
'None'
# 'None' compares True which might not be expected

1
はい、考えすぎないでください。のstr(my)代わりに使用しますmy.message
クリスチャンロング

1

str(myexception)を使用するようにアドバイスすると、Python 2.7でUnicodeの問題が発生します。例:

str(Exception(u'δσφφδσ'))
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
UnicodeEncodeError: 'ascii' codec can't encode characters in position 0-5: ordinal not in range(128)

:(

unicode(Exception(u'δσφφδσ')) 

期待どおりに機能し、エラー文字列のコンテンツの一部にユーザー入力が含まれる場合に推奨されます


1

pzrqの投稿は使用するように言っています:

str(e)

これはまさに私が必要としたものでした。

(Unicode環境の場合、次のように表示されます:

unicode(e)

動作し、非Unicode環境で正常に動作するように見えます)

Pzrqは他にも多くの良いことを言っていましたが、すべての良いことのために私はほとんど答えを逃しました。私は50ポイントを持っていないので、機能する単純なソリューションに注意を向けさせるために彼らの答えにコメントすることはできません、そして15を持っていないので、その答えに投票することはできませんが、投稿できます(逆に感じますが、まあ)-それで私はここに投稿しています-おそらくそのためにポイントを失います...

私のポイントはpzrqの答えに注意を引くことですので、以下のすべてに気を取って見逃さないでください。この投稿の最初の数行が最も重要です。

私の物語:

私がここに来た問題は、あなたが制御できないクラスからの例外をキャッチしたい場合でした-それから何??? 考えられるすべての例外からメッセージを取得できるようにするために、コードが使用するすべての可能なクラスをサブクラス化するつもりはありません。

私は使っていました:

except Exception as e:
   print '%s (%s)' % (e.message,type(e))

これは、私たちすべてが知っているように、OPが尋ねた警告(ここに私を連れてきた)を与えます。これは、pzrqがそれを行う方法として与えます。

except Exception as e:
   print '%s (%s)' % (str(e),type(e))

しませんでした。

私はユニコード環境ではありませんが、jjcの答えは私に不思議に思ったので、私はそれを試さなければなりませんでした。このコンテキストでは、これは次のようになります。

except Exception as e:
   print '%s (%s)' % (unicode(e),type(e))

驚いたことに、これはstr(e)とまったく同じように機能しました。つまり、今はそれを使用しています。

'str(e)/ unicode(e)'が '承認されたPythonの方法'であるかどうかはわかりません。3.0に到達したときに、なぜそれが良くないのかはおそらくわかりますが、死ぬことなく予期せぬ例外(*)が発生し、そこから情報を取得しても消えることはありません...

(*) うーん。「予期しない例外」-私は途方に暮れたばかりだと思います!

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.