このコードを書かないでください:
while condition is False:
ブール条件は、大声で叫ぶためのブール条件であるため、直接テスト(または否定してテスト)できます。
while not condition:
2番目のwhileループは、「while条件がTrue:」と記述されていません。最初のループで「isFalse」をテストする必要があると感じた理由がわかります。
disモジュールを引き出して、もう少し詳しく調べてみようと思いました。私のpyparsingの経験では、関数呼び出しは完全なパフォーマンスキラーであるため、可能であれば関数呼び出しを避けるとよいでしょう。これがあなたの元のテストです:
>>> test = lambda t : t.startswith('customernum') is False
>>> dis.dis(test)
1 0 LOAD_FAST 0 (t)
3 LOAD_ATTR 0 (startswith)
6 LOAD_CONST 0 ('customernum')
9 CALL_FUNCTION 1
12 LOAD_GLOBAL 1 (False)
15 COMPARE_OP 8 (is)
18 RETURN_VALUE
CALL_FUNCTION
ここでは2つの高価なことが起こりますLOAD_GLOBAL
。LOAD_GLOBAL
Falseのローカル名を定義することで削減できます。
>>> test = lambda t,False=False : t.startswith('customernum') is False
>>> dis.dis(test)
1 0 LOAD_FAST 0 (t)
3 LOAD_ATTR 0 (startswith)
6 LOAD_CONST 0 ('customernum')
9 CALL_FUNCTION 1
12 LOAD_FAST 1 (False)
15 COMPARE_OP 8 (is)
18 RETURN_VALUE
しかし、「is」テストを完全に削除するとどうなりますか?:
>>> test = lambda t : not t.startswith('customernum')
>>> dis.dis(test)
1 0 LOAD_FAST 0 (t)
3 LOAD_ATTR 0 (startswith)
6 LOAD_CONST 0 ('customernum')
9 CALL_FUNCTION 1
12 UNARY_NOT
13 RETURN_VALUE
LOAD_xxx
とCOMPARE_OP
を簡単に折りたたんでいUNARY_NOT
ます。「isFalse」は確かにパフォーマンスの原因にはなりません。
では、関数呼び出しをまったく行わずに、行を大幅に削除できるとしたらどうでしょうか。行の最初の文字が「c」でない場合、('customernum')で始まる方法はありません。それを試してみましょう:
>>> test = lambda t : t[0] != 'c' and not t.startswith('customernum')
>>> dis.dis(test)
1 0 LOAD_FAST 0 (t)
3 LOAD_CONST 0 (0)
6 BINARY_SUBSCR
7 LOAD_CONST 1 ('c')
10 COMPARE_OP 3 (!=)
13 JUMP_IF_FALSE 14 (to 30)
16 POP_TOP
17 LOAD_FAST 0 (t)
20 LOAD_ATTR 0 (startswith)
23 LOAD_CONST 2 ('customernum')
26 CALL_FUNCTION 1
29 UNARY_NOT
>> 30 RETURN_VALUE
([0]を使用して文字列の最初の文字を取得しても、スライスは作成されないことに注意してください。これは実際には非常に高速です。)
ここで、「c」で始まる行が多数ない場合、ラフカットフィルターはすべてのかなり高速な命令を使用して行を削除できます。実際、「not t [0] =='c'」ではなく「t[0]!='c'」をテストすることで、無関係なUNARY_NOT
命令を節約できます。
したがって、ショートカットの最適化に関するこの学習を使用して、このコードを変更することをお勧めします。
while sline.startswith("customernum: ") is False:
sline = txtdb.readline()
while sline.startswith("customernum: "):
... do the rest of the customer data stuff...
これに:
for sline in txtdb:
if sline[0] == 'c' and \
sline.startswith("customernum: "):
... do the rest of the customer data stuff...
.readline()関数呼び出しも削除し、「for slineintxtdb」を使用してファイルを反復処理していることに注意してください。
Alexが最初の「customernum」行を見つけるためにまったく別のコードを提供していることはわかっていますが、大きくてもあいまいなブロック読み取りガンを引き出す前に、アルゴリズムの一般的な範囲内で最適化してみます。