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

mqxuamgl  于 2023-03-04  发布在  Python
关注(0)|答案(2)|浏览(516)

我正在编写一个从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地址随机块,导致这个错误,所以我得到这样的关键错误:密钥错误:"ipv4前缀"
我知道为什么我会得到这个错误,所以我尝试删除整个条目与ipv6Prefix,所以我添加了这部分到我的代码:

if data[i]["prefixes"] == "ipv6Prefix":
        data.pop(i)

对于这个,我得到TypeError:不可散列类型:"dict"对我来说是新的,我也试过这个,就像有人在另一个问题中指出的那样,但它不起作用。

del data[ipv6Prefix]

现在我的最终代码是这样的,并得到这个错误:TypeError:列表索引必须是整数或切片,而不是可以理解的字符串。

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循环中忽略它们?
我找到了this问题,但答案根本不符合我的代码。
我的代码有什么问题?
我尝试了几种方法,如deldict.pop(),但仍然出现错误。

rdrgkggo

rdrgkggo1#

你有两个选择:Look Before You Leap or Easier to Ask Forgiveness than Permission。简而言之:

      • 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。在你的例子中,你知道有些对象 * 不 * 有ipv4Prefix,所以我认为LBYL在这里更合适。

yhuiod9q

yhuiod9q2#

  • 那么我如何删除带有“ipv6 Prefix”的条目,或者更确切地说,在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本身以省略包含ipv6Prefixlist 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],但是idata['prefixes']中的一个 dictionary 的副本,因此如果试图执行 * .pop(i) *,它将引发一个错误。
您可以循环通过enumerate(data['prefixes'])(而不是仅仅 * data['prefixes'] *)来跟踪与i相关联的索引,但请记住,循环通过列表到pop多个项目[来自同一列表]是 * 不 * 可取的。例如,如果您从列表[index=1]弹出第二个项目,则其后所有项的索引减1;因此,如果您接下来需要弹出列表中 * 原来 * 的第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,你也可以像data['prefixes'][::-1]一样使用slicing,我只是认为使用这个函数更好的可读性,因为它使它所做的事情非常明显。

if data[i]["prefixes"] == "ipv6Prefix":
  • 对于这个,我得到了TypeError: unhashable type: 'dict',这对我来说是新的 *

i是一个字典(如错误消息所述,它是不可散列的),因此不能像 * ....data[i]... * 那样用作键。

  • 所以我得到了这样的键错误:x 1米30英寸1x *

可能来自 * array = [i['prefix'] for i in data['ipv4Prefix']] * 中的data['ipv4Prefix']位,因为data没有密钥ipv4Prefix;***for i in data['prefixes']*中的一些i可能会,但是使用 * if 'ipv4Prefix' in i: del i****没有意义,因为i是正在循环通过的列表中的项的 * 副本
您可以尝试使用.remove,如
data['prefixes'].remove(i)
[而不是 * del i *],但我不认为这是非常有效的。列表解析绝对是我在这种情况下的首选方法[也可能被认为是最“Python”的方法]。

相关问题