如何使用 python 删除或忽略 JSON 文件中的条目?

问题描述 投票:0回答:2

我正在编写从 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()
,但我仍然出错。

python json
2个回答
0
投票

您有两个选择:三思而后行或请求宽恕比请求许可更容易。简而言之:

  • LBYL:进行
    if
    检查以确保
    ipv4Prefix
    存在
  • EAFP:假设
    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 更适合这里。


0
投票

那么我怎样才能删除带有“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”的方法]。

© www.soinside.com 2019 - 2024. All rights reserved.