新手咨询:Python双层循环中`ip not in i`未报错的原因
ip not in i的i看似未定义却能运行? 我是一名Python新手。请问为何这段脚本能够正常运行,即便在ip not in i的判断中i变量看似未定义?
该脚本用于对比通过paramiko SSH连接获取的ARP表列表match_data与我的IP列表match_ip,我希望实现的功能是:打印匹配到的IP与MAC地址,若IP不在ARP表中则打印ip + "NO MAC ADDRESS"。
原脚本代码
for ip in match_ip: for i in match_data: if ip in i: print re.search((ip+'\s+'),i).group(0),mac.search(i).group(0) break if ip not in i: print ip + ' NO MAC ADDRESS'
运行输出
C:\Python27\python.exe C:/Python2/Get_mac_from_arp.py !!!Connecting SSH!!! 10.240.184.103 30e4.db80.b699 10.240.184.104 7c2f.802d.61e5 10.240.184.105 7c2f.8072.40fc 10.240.184.106 e05f.b982.5720 10.240.178.11 NO MAC ADDRESS 10.240.184.177 e05f.b982.5752 10.240.184.178 7c2f.802a.782a 10.240.184.179 30e4.db80.b6ec 10.240.184.180 7c2f.802a.782b Process finished with exit code 0
嘿,这个问题刚学Python的时候真的很容易踩坑!我来给你拆解一下:
首先你觉得i未定义,但实际上在Python里,for循环结束后,循环变量会保留最后一次迭代的值。也就是说,不管内层的for i in match_data是正常跑完所有元素,还是中途触发break跳出,i都会是循环最后一次接触到的那个元素——要么是匹配到的项,要么是match_data的最后一项。所以你的if ip not in i判断其实是在拿当前ip和这个“残留”的i做比较,而不是判断ip在整个match_data里都不存在。
那为什么你的脚本看起来“正常运行”了?纯粹是巧合!在你的测试案例里,那个找不到的IP(10.240.178.11)刚好不在match_data的最后一项里,所以触发了打印。但这个逻辑是有严重问题的:比如如果某个ip不在match_data的前几项,但恰好存在于最后一项,你的代码会错误地认为它不存在,打印NO MAC;反过来,如果某个ip在前面的项里被找到(触发break),但最后一项不包含这个ip,你的代码会在打印匹配结果后,又多打印一次NO MAC,这就完全不符合预期了!
正确的写法应该是这样的:
我们可以用一个标志位来记录是否找到匹配项,逻辑会更清晰可靠:
import re # 原代码没写,实际运行要导入re模块哦 for ip in match_ip: found = False # 初始化标志位:默认未找到匹配 for i in match_data: if ip in i: # 先判断匹配结果是否存在,避免None.group()报错 ip_result = re.search(ip + '\s+', i) mac_result = mac.search(i) if ip_result and mac_result: print(ip_result.group(0).strip(), mac_result.group(0).strip()) found = True # 找到匹配,更新标志位 break if not found: # 只有完全没找到的时候才打印提示 print(ip + ' NO MAC ADDRESS')
这样修改后,不管match_data的顺序如何,都能准确判断每个IP是否存在于ARP表中,不会再出现逻辑漏洞啦。
内容的提问来源于stack exchange,提问作者Dover

