我正在编写从 JSON 文件中提取数据的代码,这里是 JSON 文件:Google CDN
这是 JSON 代码示例:
{
"syncToken": "1677578581095",
"creationTime": "2023-02-28T02:03:01.095938",
"prefixes": [{
"ipv4Prefix": "34.80.0.0/15",
"service": "Google Cloud",
"scope": "asia-east1"
}, {
"ipv4Prefix": "34.137.0.0/16",
"service": "Google Cloud",
"scope": "asia-east1"
}, {
"ipv4Prefix": "35.185.128.0/19",
"service": "Google Cloud",
"scope": "asia-east1"
}, {
"ipv6Prefix": "2600:1900:40a0::/44",
"service": "Google Cloud",
"scope": "asia-south1"
},
我知道问题出在哪里,但无法通过本网站上的解决方案解决问题,每次都会出现另一个错误。
这是我的代码
import json
f = open('cloud.json')
data = json.load(f)
array = []
for i in data['prefixes']:
array = [i['prefix'] for i in data['ipv4Prefix']]
f_path = (r"ip.txt")
with open (f_path ,'w') as d:
for lang in array:
d.write("{}\n".format(lang))
f.close()
基本上我只想提取 ipv4 地址,但是块中随机有一些 ipv6 地址导致了这个错误,所以我得到这样的关键错误:KeyError: 'ipv4Prefix'
我知道为什么会出现此错误,所以我尝试使用 ipv6Prefix 删除整个条目,因此我将这部分添加到我的代码中:
if data[i]["prefixes"] == "ipv6Prefix":
data.pop(i)
对于这个我得到 TypeError: unhashable type: 'dict' 这对我来说是新的,我也试过这个,因为有人在另一个问题中指出但它没有用。
del data[ipv6Prefix]
现在我的最终代码是这样的并得到这个错误:TypeError: list indices must be integers or slice, not str which is understanded.
import json
f = open('cloud.json')
data = json.load(f)
array = []
for i in data['prefixes']:
if [i]["prefixes"] == ['ipv6Prefix']:
data.pop(i)
array = [i['prefix'] for i in data['ipv4Prefix']]
f_path = (r"ip.txt")
with open (f_path ,'w') as d:
for lang in array:
d.write("{}\n".format(lang))
f.close()
那么我怎样才能删除带有“ipv6Prefix”的条目,或者更确切地说,在我的 for 循环中忽略它们?
我发现这个问题,但答案根本不符合我的代码。
我的代码有什么问题?
我尝试了几种方法,例如
del
和dict.pop()
,但我仍然出错。
您有两个选择:三思而后行或请求宽恕比请求许可更容易。简而言之:
if
检查以确保ipv4Prefix
存在ipv4Prefix
存在但捕获异常(在这种情况下为KeyError
)这里有一些代码演示了这两种方法。它不包括写出结果。
import json
def lbyl(data: dict):
"""Look before you leap"""
ipv4s = []
for prefix in data["prefixes"]:
# Ensure that "ipv4Prefix" exists
if "ipv4Prefix" in prefix:
ipv4s.append(prefix["ipv4Prefix"])
return ipv4s
def eafp(data: dict):
"""Easier to Ask Forgiveness than Permission"""
ipv4s = []
for prefix in data["prefixes"]:
try:
ipv4s.append(prefix["ipv4Prefix"])
except KeyError:
# This happens when "ipv4Prefix" is not in prefix
pass
return ipv4s
def get_data(path) -> dict:
with open(path) as f:
return json.load(f)
if __name__ == "__main__":
data = get_data("cloud.json")
print(lbyl(data))
print(eafp(data))
使用哪种风格是主观的。 Python 以偏爱 EAFP 着称,但如果在正常操作中预计会出现错误,我更喜欢使用 LYBL。在你的情况下,你知道有些物体 not 有
ipv4Prefix
,所以我认为 LBYL 更适合这里。
那么我怎样才能删除带有“ipv6Prefix”的条目,或者更好地说,在我的 for 循环中忽略它们?
您可以跳过/忽略包含
ipv6Prefix
的前缀和if...continue
:
# import json
# with open('cloud.json') as f: data = json.load(f) ## safer than f=open...
with open ("ip.txt" ,'w') as d:
for prefix_i in data['prefixes']:
# if 'ipv6Prefix' not in prefix_i: d.write("{prefix_i}\n") ## OR
if 'ipv6Prefix' in prefix_i: continue
d.write("{}\n".format(prefix_i))
## list-comprehension INSTEAD OF for-loop:
# d.write('\n'.join(str(p) for p in data['prefixes'] if 'ipv6Prefix' not in p))
您只能写包含
ipv4Prefix
和if 'ipv4Prefix' in...
的前缀
with open ("ip.txt" ,'w') as d:
for prefix_i in data['prefixes']:
if 'ipv4Prefix' in prefix_i: d.write("{}\n".format(prefix_i))
您可以改变
data
本身以省略包含 ipv6Prefix
的前缀与 list comprehension:
data['prefixes'] = [p for p in data['prefixes'] if 'ipv6Prefix' not in p]
您可以使用
ipv4Prefix
:将包含
json.dump
的前缀列表保存为 JSON
## to just save the list as a variable:
# ipv4Prefixes = [p for p in data['prefixes'] if 'ipv4Prefix' in p]
with open('ipv4Prefixes.json', w) as f:
json.dump([p for p in data['prefixes'] if 'ipv4Prefix' in p], f)
得到这个错误:
TypeError: list indices must be integers or slices, not str
这可能是由于
if [i]["prefixes"] == ['ipv6Prefix']:
线; [i]
是一个只有一个项目的 list [i
,这是一本字典],所以 [i]["prefixes"]
没有任何意义。您可以改用 if 'ipv6Prefix' in i["prefixes"]
,但是您要在该块中完成的工作存在更多问题 [我将在下一节中解释]。
# for i in data['prefixes']... data.pop(i)
.pop
方法只需要一个 integer 作为输入 [它必须是您要从该列表中删除的项目的 index],但是 i
是里面的 dictionary 的副本data['prefixes']
,所以如果尝试执行它,.pop(i)
会引发错误。
enumerate
(data['prefixes'])
(而不仅仅是data['prefixes']
)以跟踪相关联的索引i
,但请记住循环遍历列表以pop
NOT 完全不建议 [来自同一列表] 的多个项目。例如,如果您从列表 [index=1] 中弹出第二个项目,那么它之后的所有项目的索引都会减少 1;所以如果你接下来需要弹出originally列表中的第5项,enumerate
会告诉你它的索引是4,但在执行.pop(1)
...后它实际上变成了3
你 可以 如下所示反向循环列表(但我之前建议的列表理解方法不是更简单吗?)
for pi, p in enumerate(reversed(data['prefixes']), 1-len(data['prefixes'])):
if 'ipv6Prefix' in p["prefixes"]: data['prefixes'].pop(pi)
reversed
,您还可以使用 slicing,如 data['prefixes'][::-1]
。我只是认为使用该函数更利于可读性,因为它使它在做什么非常明显。
if data[i]["prefixes"] == "ipv6Prefix":
对于这个我得到
这对我来说是新的TypeError: unhashable type: 'dict'
i
是一本字典(如错误消息所述,它是不可散列的),因此不能像 ....data[i]...
尝试的那样用作键。
所以我得到这样的关键错误:
KeyError: 'ipv4Prefix'
可能来自
data['ipv4Prefix']
中的
array = [i['prefix'] for i in data['ipv4Prefix']]
位,因为data
没有密钥ipv4Prefix
; some i
s 在 for i in data['prefixes']
可能,但是使用 if 'ipv4Prefix' in i: del i
没有意义 因为 i
是循环列表中项目的 copy虽然。
.remove
像 data['prefixes'].remove(i)
[而不是 del i
],但我认为这不是很有效。在这种情况下,列表理解绝对是我的首选方法[并且可能被认为是这里最“pythonic”的方法]。