Python:1行でステートメントを試してください


97

Pythonでtry / exceptionを1行に変換する方法はありますか?

何かのようなもの...

b = 'some variable'
a = c | b #try statement goes here

b宣言された変数はどこにあり、cそうではありません...したがってc、エラーがスローされ、...にaなりbます。

回答:


63

Pythonではtry/exceptブロックを1行に圧縮する方法はありません。

また、他の動的言語のように、Pythonに変数が存在するかどうかを知らないのは悪いことです。より安全な方法(および一般的なスタイル)は、すべての変数を何かに設定することです。設定されない可能性がある場合は、None最初に設定します(または0''より適切な場合は、または何か)。


あなたがいる場合行うあなたが最初に興味を持っているすべての名前を割り当てるには、オプションを持っています。

  • 最良のオプションはifステートメントです。

    c = None
    b = [1, 2]
    
    if c is None:
        a = b
    else:
        a = c
    
  • ワンライナーオプションは条件式です。

    c = None
    b = [1, 2]
    a = c if c is not None else b
    
  • 一部の人々orはこれを行うためにの短絡動作を悪用します。これはエラーが発生しやすいので、私は決して使用しません。

    c = None
    b = [1, 2]
    a = c or b
    

    次の場合を考えてみましょう。

    c = []
    b = [1, 2]
    a = c or b
    

    この場合、aおそらくはであるはずです[]、ブール値のコンテキストではfalseである[1, 2]ため[]です。間違っている可能性のある値がたくさんあるので、私はorトリックを使用しません。(これは、人々がif foo:意味するときに言うときに遭遇するのと同じ問題if foo is not None:です。)


ありがとう。問題は、実際にテストしようとしているdjangomodel.objects.getクエリです。データが見つからない場合、.getはエラーを返します...それはNoneを返しません(これは私を悩ませます)
Brant

@Brant、わかりました。その状況は、変数が設定されているかどうかを確認するのとは少し異なります(Pythonでは変数が宣言されていません)。Pythonの典型的なスタイルは、エラーを値として返すよりも例外を発生させることを好むことです。これは私たちの多くが実際に気に入っています。毎回操作の戻りコードをチェックする必要があり、そうでない場合にエラーを追跡するのに苦労することは、Pythonを作成するときにCについて絶対に見逃せないことです。いずれにせよ、それは議論されてきましたが、try/exceptブロックの1行の構文はありません。幸いなことに、回線は安価なので、4回線のソリューションが適しています。;-)
マイクグラハム

それはディクテーション内のタプルの大きなセットの一部です...私は物事を少し短くしようとしていました
ブラント

2
get例外が必要ない場合は使用しないでください。filter代わりに使用してください。
jcdyer 2010年

@MikeGraham良い答え-短絡がエラーを起こしやすい理由のヒント(リンク?)がいいでしょう。
kratenko 2014

85

これはひどくハックですが、デバッグ用の一連のアクションを記述したいときにプロンプ​​トで使用しました。

exec "try: some_problematic_thing()\nexcept: problem=sys.exc_info()"
print "The problem is %s" % problem[1]

ほとんどの場合、私はno-single-line-try-except制限にまったく悩まされていませんが、実験しているときに、readlineがインタラクティブインタープリターでコードのチャンク全体を一度に呼び出すようにしたい場合は、なんとか調整できるので、このちょっとしたコツが重宝します。

あなたが達成しようとしている実際の目的のために、あなたは試みるかもしれませんlocals().get('c', b); 理想的には、ローカルコンテキストの代わりに実際の辞書を使用するか、設定されているかどうかに関係なく実行する前にcをNoneに割り当てる方がよいでしょう。


26
ねえ、これは質問に答えます!:)
スティーブベネット

4
この答えが大好きです、非常に厄介ですが、私が好きなように1行です。
パトリッククック

これが答えです!problem[0]その関数が返すものを返しますか?
SIslam 2015

5
Execはコードの臭いであり、他に何も機能しない限り避ける必要があります。1行のコードが非常に重要な場合、これは機能しますが、1行が非常に重要である理由を自問する必要があります。
Gewthen 2015

4
明らかに本番用ではありませんが、厄介なデバッグセッションに必要なものです。
ThorSummoner 2016


13

別の方法は、コンテキストマネージャーを定義することです。

class trialContextManager:
    def __enter__(self): pass
    def __exit__(self, *args): return True
trial = trialContextManager()

次に、withステートメントを使用して、1行のエラーを無視します。

>>> with trial: a = 5      # will be executed normally
>>> with trial: a = 1 / 0  # will be not executed and no exception is raised
>>> print a
5

ランタイムエラーが発生しても例外は発生しません。のtry:ないようなものexcept:です。


1
これは素晴らしい!明示的なtry / exceptionがないので、コンテキストマネージャーがエラーを処理する方法を簡単に説明できますか?
パトリック

10

予想される例外が限定されたpoke53280回答のバージョン。

def try_or(func, default=None, expected_exc=(Exception,)):
    try:
        return func()
    except expected_exc:
        return default

そしてそれはとして使用することができます

In [2]: try_or(lambda: 1/2, default=float('nan'))
Out[2]: 0.5

In [3]: try_or(lambda: 1/0, default=float('nan'), expected_exc=(ArithmeticError,))
Out[3]: nan

In [4]: try_or(lambda: "1"/0, default=float('nan'), expected_exc=(ArithmeticError,))
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
[your traceback here]
TypeError: unsupported operand type(s) for /: 'str' and 'int'

In [5]: try_or(lambda: "1"/0, default=float('nan'), expected_exc=(ArithmeticError, TypeError))
Out[5]: nan

「expected_exc =(Exception、)」のカンマは何ですか?説明してもらえますか?
ibilgen

1
@ibilgenコンマは、式をタプルに変換します。書く(Exception)ことは括弧を省くことと同じです。(Exception, )これが1つのエントリを持つタプル(リストのようなもの)であることをインタプリタに通知します。この例ではこれが使用されているためexpected_exc、複数の例外が発生する可能性があります。
miile7


5

問題は、実際にテストしようとしているdjangomodel.objects.getクエリです。データが見つからない場合、.getはエラーを返します...それはNoneを返しません(これは私を悩ませます)

次のようなものを使用します。

print("result:", try_or(lambda: model.objects.get(), '<n/a>'))

try_orは、ユーザーが定義したユーティリティ関数です。

def try_or(fn, default):
    try:
        return fn()
    except:
        return default

必要に応じて、あなたはに受け入れられた例外の種類を制限することができNameErrorAttributeErrorなど


5

2本の線を使ってみませんか。大丈夫ですか ?

>>> try: a = 3; b= 0; c = a / b
... except : print('not possible'); print('zero division error')
...
not possible
zero division error

4

あなたは使用して名前空間の辞書にアクセスすることによってそれを行うことができますvars()locals()またはglobals()あなたの状況に最も適している方、。

>>> b = 'some variable'
>>> a = vars().get('c', b)

3
これは、変数が設定されているかどうかを確認するのとまったく同じようには機能しません(ただし、特定のスコープに関心がある場合は機能します)。また、ewwwwwwww .....
Mike Graham

2

あなたはdjangoを使用していると言いました。あなたがしていることに意味があるなら、あなたは使いたいかもしれません:

my_instance, created = MyModel.objects.get_or_create()

createdTrueまたはFalseになります。多分これはあなたを助けるでしょう。


2

WalterMundtに触発されたPython3で動作します

exec("try:some_problematic_thing()\nexcept:pass")

複数行を1行に

exec("try:\n\tprint('FirstLineOk')\n\tsome_problematic_thing()\n\tprint('ThirdLineNotTriggerd')\nexcept:pass")

追伸:Execは、制御できないデータで使用するのは安全ではありません。


1

実際に例外を管理する必要がある場合:
(poke53280の回答から変更)

>>> def try_or(fn, exceptions: dict = {}):
    try:
        return fn()
    except Exception as ei:
        for e in ei.__class__.__mro__[:-1]:
            if e in exceptions: return exceptions[e]()
        else:
            raise


>>> def context():
    return 1 + None

>>> try_or( context, {TypeError: lambda: print('TypeError exception')} )
TypeError exception
>>> 

例外がサポートされていない場合、期待どおりに発生することに注意してください。

>>> try_or( context, {ValueError: lambda: print('ValueError exception')} )
Traceback (most recent call last):
  File "<pyshell#57>", line 1, in <module>
    try_or( context, {ValueError: lambda: print('ValueError exception')} )
  File "<pyshell#38>", line 3, in try_or
    return fn()
  File "<pyshell#56>", line 2, in context
    return 1 + None
TypeError: unsupported operand type(s) for +: 'int' and 'NoneType'
>>> 

また、Exceptionが指定されている場合は、以下のいずれかに一致します。
BaseException高いので一致しません)

>>> try_or( context, {Exception: lambda: print('exception')} )
exception

0

これは@surendra_benによって提供された答えのより簡単なバージョンです

a = "apple"try: a.something_that_definitely_doesnt_exist
except: print("nope")

...

nope

0

with1行で構文を使用します。

class OK(): __init__ = lambda self, isok=None: setattr(self, 'isok', isok); __enter__ = lambda self: None; __exit__ = lambda self, exc_type, exc_value, traceback: (True if not self.isok or issubclass(exc_type, self.isok) else None) if exc_type else None

エラーを無視します。

with OK(): 1/0

指定されたエラーを無視します:

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