ホームページ > バックエンド開発 > Python チュートリアル > Python コードの効率を向上させる方法を検討する

Python コードの効率を向上させる方法を検討する

WBOYWBOYWBOYWBOYWBOYWBOYWBOYWBOYWBOYWBOYWBOYWBOYWB
リリース: 2016-06-16 08:43:30
オリジナル
1532 人が閲覧しました

最初の動き: スネークが 7 インチに到達: ボトルネックの特定

まず、最初のステップはボトルネックを特定することです。簡単な例を挙げると、ある関数は 1 秒から 0.9 秒に最適化でき、別の関数は 1 分から 30 秒に最適化できます。コストが同じで時間制限が 1 つしか解決できない場合、どちらを最適化する必要があります。最適化されましたか?もちろん、欠点の原則に基づいて、私は 2 番目のオプションを選択します。

経験豊富なプログラマーはここで間違いなく躊躇するでしょう、ちょっと待ってください。関数?では、やはり通話数を考慮する必要があるのでしょうか?最初の関数をプログラム全体で 100,000 回呼び出す必要があり、2 番目の関数をプログラム全体で 1 回呼び出す必要がある場合、これは必ずしも当てはまりません。この例は、プログラムのボトルネックが一見しただけでは見えない場合があることを説明するために示したものです。上記の選択でも、プログラマーとしては、ほとんどの場合、1 秒から 0.9 秒まで最適化「できる」関数よりも、1 分から 30 秒まで最適化「できる」関数の方が理解しやすいと感じるはずです。改善の余地がたくさんあるので注意が必要です。

ということで、くだらない話をした後、最初のヒント、プロフィールを紹介しましょう。これはプログラムのボトルネックを特定するための Python 独自のツールです。プロファイル、cProfile、hotshot の 3 つのオプションが提供されます。また、内蔵型と外付け型に分かれます。ただし、個人的には外部 cProfile 1 つで十分だと考えています。その心理は次のとおりです。

python -m profile 逗比程序.py
ログイン後にコピー

このトリックの効果は、関数が呼び出された回数、合計時間、この関数のサブ関数によって費やされた時間、各サブ関数にかかった時間などの一連の内容を出力します。時間など百聞は一見にしかず:

ファイル名:lineno(関数): ファイル名:lineno(関数名)
ncalls: この男は合計何回電話されました
tottime: この人は合計どれくらいの時間を費やしましたか、つまり内部関数のヤツを取り除くのにどれくらいの時間がかかりました
コールごと: 各コールにかかった平均時間、合計時間を ncalls で割った
Cumtime: この製品とそのすべての内部機能の合計コスト
percall: 上記の percall に似ていますが、累積時間を ncalls
で割ったものです。 最適化する価値のあるポイントを見つけて、それに取り組んでください。

2 番目の動き: One Snake Zen: 1 つの動きだけ

私が初めて Python に触れたとき、先輩が、Python には素晴らしい理想がある、それを使う人全員が全く同じプログラムを書けることを望んでいる、と言ったのを覚えています。 Python の禅:

それを行う明白な方法は 1 つ、できれば 1 つだけあるべきです

そこで、Python の専門家である Zen マスターが、いくつかの一般的な関数を記述する唯一の方法を提供します。伝説的な PythonWiKi:PerformanceTips を参照して、「だまされてはいけない」と「だまされてはいけません」をいくつかまとめました。

文字列を結合するときに混乱しないでください:

s = "" for substring in list: s += substring
ログイン後にコピー

姜子が欲しい:

s = "".join(slist)
ログイン後にコピー

文字列をフォーマットするときはいじらないでください:

out = "<html>" + head + prologue + query + tail + "</html>"
ログイン後にコピー

姜子が欲しい:

out = "<html>%s%s%s%s</html>" % (head, prologue, query, tail)
ログイン後にコピー

不要な場合はループを使用しないでください。たとえば、Jiang Zi を使用しないでください。

newlist = [] for word in oldlist: newlist.append(word.upper())
ログイン後にコピー

姜子が欲しい:

newlist = map(str.upper, oldlist)
ログイン後にコピー

または姜子:

newlist = [s.upper() for s in oldlist]
ログイン後にコピー

辞書の初期化、より一般的に使用される:

wdict = {} for word in words: if word not in wdict: wdict[word] = 0 wdict[word] += 1
ログイン後にコピー

繰り返される単語が多すぎる場合は、多くの判断を省くために Jiangzi モードの使用を検討できます:

wdict = {} for word in words: try: wdict[word] += 1 except KeyError: wdict[word] = 1
ログイン後にコピー

関数呼び出しの数をできるだけ減らし、内部ループに置き換えます。たとえば、間違いを犯さないでください。

x = 0 def doit1(i): global x x = x + i list = range(100000) t = time.time() for i in list: doit1(i)
ログイン後にコピー

姜子が欲しい:

x = 0 def doit2(list): global x for i in list: x = x + i list = range(100000) t = time.time() doit2(list)
ログイン後にコピー

3手目:スネークスナイパー:高速探索

このトリックの一部は、IBM: Python コード パフォーマンス最適化テクニックから来ています。検索アルゴリズムの最高の状態は、アルゴリズムの複雑さ O(1) です。それがハッシュテーブルです。幸いなことに、私は学部生のときにいくつかのデータ構造を学びました。 Python のリストはリンク リストのようなメソッドを使用して実装されていることに注意してください。リストが非常に大きい場合、list_a の if X を使用して膨大な項目の中から検索して判断するのは非常に非効率です。

Python のタプルを使用することはほとんどないので、コメントしません。私がよく使う他の 2 つは set と dict です。これら 2 つはハッシュ テーブルの実装方法に似ています。

したがって、あまり紫色にならないようにしてください:

k = [10,20,30,40,50,60,70,80,90] for i in xrange(10000): if i in k: #Do something continue
ログイン後にコピー

姜子が欲しい:

``` k = [10,20,30,40,50,60,70,80,90] k_dict = {i:0 for i in k}
ログイン後にコピー

まずリストを辞書に変換します

for i in xrange(10000): if i in k_dict: #Do something continue ```
ログイン後にコピー

リストの共通部分を探します。嫉妬しないでください:

list_a = [1,2,3,4,5]
list_b = [4,5,6,7,8]
list_common = [a for a in list_a if a in list_b]
ログイン後にコピー

姜子が欲しい:

list_a = [1,2,3,4,5]
list_b = [4,5,6,7,8]
list_common = set(list_a)&set(list_b)
ログイン後にコピー

4 番目のトリック: Little Snake...: 名前は思いつきません。ちょっとしたヒントだけです

変数交換には中間変数は必要ありません: a, b = b, a (ここに落とし穴があります。私は今でも深く覚えています: True、False = False、True)
Python2.x を使用する場合は、range の代わりに xrange を使用します。Python3.x を使用する場合、range はすでに xrange であり、xrange は存在しません。 xrange は range のようなリストを生成しませんが、反復子を生成してメモリを節約します。
x>y および y>z の代わりに x>y>z を使用できます。より効率的で読みやすくなりました。もちろん理論上は x>y
一般的に add(x,y) は a+b よりも高速ですか?これについては疑問があったので、実験してみました。第一に、add は直接使用できず、インポート演算子が必要です。第二に、実験の結果、add(x,y) は a+b ほど高速ではないことがわかりました。可読性が犠牲になることは言うまでもありません。
while 1 は確かに while True よりわずかに高速です。 2 つの実験を行ったところ、約 15% 高速になりました。
5 番目のトリック: ヘビより優れたヘビはありません: コードを超えたパフォーマンス

コードのほかに、ハードウェアとは別に、ここでは pypy を強くお勧めします。 pypy はジャストインタイムのコンパイラです。このコンパイラの特徴は、静的コンパイラとは異なり、1 つの文をコンパイルして 1 つの文を実行することです。Zhihu で非常に鮮やかな比喩を目にしました。

あなたが監督であると仮定すると、静的コンパイルとは、俳優に脚本全体を暗記し、それを 1 時間継続的に実行するよう依頼することを意味します。動的編集とは、俳優に 2 分間演技してもらい、その後考えて台本をもう一度読み、その後 2 分間演技することを意味します...

動的コンパイルと静的コンパイルにはそれぞれ独自の利点があり、それは映画で演技するかドラマで演技するかによって異なります。

さらに、C コードを Python に組み込むことができる Cython もあります。使用頻度は控えめですが、いざという時には役に立ちます。

関連ラベル:
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
最新の問題
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート