Bir*_*irt 2 python loops readline
我正在将文本格式的Databasedump的几个部分导入MySQL,问题是在有趣的数据之前,非常有趣的东西面前.我写了这个循环来获取所需的数据:
def readloop(DBFILE):
txtdb=open(DBFILE, 'r')
sline = ""
# loop till 1st "customernum:" is found
while sline.startswith("customernum: ") is False:
sline = txtdb.readline()
while sline.startswith("customernum: "):
data = []
data.append(sline)
sline = txtdb.readline()
while sline.startswith("customernum: ") is False:
data.append(sline)
sline = txtdb.readline()
if len(sline) == 0:
break
customernum = getitem(data, "customernum: ")
street = getitem(data, "street: ")
country = getitem(data, "country: ")
zip = getitem(data, "zip: ")
Run Code Online (Sandbox Code Playgroud)
Textfile非常庞大,所以只需循环直到第一个想要的条目需要花费很多时间.任何人都有一个想法,如果这可以更快地完成(或者如果整个方式我修复这不是最好的主意)?
提前谢谢了!
请不要写这段代码:
while condition is False:
Run Code Online (Sandbox Code Playgroud)
布尔条件是大声喊叫的布尔值,因此可以直接测试(或否定和测试)它们:
while not condition:
Run Code Online (Sandbox Code Playgroud)
你的第二个while循环不是写成"条件为真:",我很好奇你为什么觉得需要在第一个中测试"是假的".
拉出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
Run Code Online (Sandbox Code Playgroud)
两个昂贵的东西在这里发生,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
Run Code Online (Sandbox Code Playgroud)
但是,如果我们完全放弃'是'测试怎么办?:
>>> 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
Run Code Online (Sandbox Code Playgroud)
我们已经崩溃了LOAD_xxx,COMPARE_OP并且很简单UNARY_NOT."是假的"肯定是没有帮助性能导致任何.
现在如果我们可以完全消除一条线而不进行任何函数调用.如果该行的第一个字符不是'c',则它无法以startwith('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
Run Code Online (Sandbox Code Playgroud)
(请注意,使用[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...
Run Code Online (Sandbox Code Playgroud)
对此:
for sline in txtdb:
if sline[0] == 'c' and \
sline.startswith("customernum: "):
... do the rest of the customer data stuff...
Run Code Online (Sandbox Code Playgroud)
请注意,我还删除了.readline()函数调用,并使用"for tline in txtdb"迭代文件.
我意识到Alex完全提供了不同的代码体,用于找到第一个"customernum"行,但我会尝试在算法的一般范围内进行优化,然后再拔出大而模糊的块读取枪.
| 归档时间: |
|
| 查看次数: |
2854 次 |
| 最近记录: |