请不要写这段代码:
while condition is False:
布尔条件是大声哭泣的布尔值,因此可以直接测试(或否定和测试)它们:
while not condition:
你的第二个while循环没有写成“while condition is True:”,我很好奇为什么你觉得需要在第一个循环中测试“is False”。
拉出 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
并且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
现在,如果我们可以在不进行任何函数调用的情况下对一行进行一些粗略的消除会怎样。如果该行的第一个字符不是'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”开头的行,粗切过滤器可以使用所有相当快的指令来消除一行。事实上,通过测试 "t[0] != 'c'" 而不是 "not 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 sline in txtdb”对文件进行迭代。
我意识到 Alex 提供了完全不同的代码体来查找第一个“customernum”行,但我会尝试在算法的一般范围内进行优化,然后再拿出大而晦涩的块读取枪。