3 に答える
コードを作成するときは常に、パフォーマンス、可読性、正確性、拡張性、保守性などのバランスを取る必要があります。残念ながら、多くの場合、これらの方向のコードを同時に改善することはできません。たとえば、高速なものは読みにくい場合があります。
Python で が推奨される理由の 1 つは、try..except
多くの場合、コードが使用されるすべての方法を予測できないためです。そのため、特定の条件が存在するかどうかを確認するよりも、特定のクラスのエラーをキャッチする方が一般的です。発生する可能性があります。したがってtry..except
、コードをより再利用可能にすることができます。
ただし、節に頻繁に到達しているtry..except
場合は遅いことも事実です。except
例外が発生しないようにそのブロックをコーディングし、try..except を使用して頻度の低い条件をキャッチする方法はありますか?
そうでない場合は、効率のために、try..except を使用しないことを選択できます。プログラミングには厳格なルールはほとんどありません。懸念事項のバランスに基づいて方法を選択する必要があります。
例外をキャッチするのは適度に高価であることは事実です(いくつかのタイミングについては以下を参照)。これをプログラムのボトルネックにしたくないでしょうが、あなたが示す例では、例外をキャッチすることは非常に小さな部分になりますModel.objects.get
SQL クエリを構築し、それをデータベース サーバーに送信し、データベースがそのようなオブジェクトがないことを報告するのを待つ必要がある呼び出しと比較して、ランタイムの。
いくつかの例のタイミング。関数f2
は例外をスローしてキャッチしますが、例外f1
を使用せずに同じ機能を実装します。
d = dict()
def f1():
if 0 in d: return d[0]
else: return None
def f2():
try: return d[0]
except KeyError: return None
>>> timeit(f1)
0.25134801864624023
>>> timeit(f2)
2.4589600563049316
そしてf3
、Django の ORM を介して (同じマシンで実行されている) データベースから存在しないオブジェクトを取得しようとします。
def f3():
try:
MyModel.objects.get(id=999999)
except MyModel.DoesNotExist:
pass
これには、次の約 400 倍の時間がかかります(デフォルトの反復が完了f2
するまで待ちたくありませんでした)。number=1000000
>>> timeit(f3, number=1000)
1.0703678131103516
この関数の速度を最適化しようとしている場合は、実際のボトルネックである可能性が高いものに注目する必要があります。3 つのデータベース クエリは、それぞれがオペレーティング システムのコンテキスト スイッチを引き起こしますが、ほぼ確実に、例外をキャッチするよりも桁違いに時間がかかります。コードをできるだけ速くしたい場合は、3 つのデータベース クエリをすべて 1 つに結合することから始めます。
auth_objects = UserSocialAuth.objects.filter(user=self, provider__in=('facebook', 'foursquare', 'twitter'))
オブジェクトをループします。provider__in
これら 3 つのプロバイダーがデータベース内にある唯一のプロバイダーである場合、フィルターは不要な場合があります。