创建字典时使用 range() 作为值

Using range() as a value when creating a dictionary

我正在尝试使用 range() 在自定义范围内的字典列表中填写值。

我有这个代码:

import requests
import json
import time

test = []
for x in range(5000,5020):
    page_url = f'https://api.jikan.moe/v4/anime/{x}/full'
    response = requests.get(page_url)
    json_data = json.loads(response.text)
    test.append(json_data)
    time.sleep(1)

anime_data = []
for dic in test:
    anime = {
        'call_id': range(5000,5020),
        'title': dic.get('data',{}).get('title','title not found'),
        'mal_id': dic.get('data',{}).get('mal_id', 'id not found'),
        'url': dic.get('data',{}).get('url', 'url not found')
    }
    anime_data.append(anime)

目标是使用 5000 到 5020 的数字作为每个字典的 'call_id' 键,这样输出看起来像:

[{'call_id': 5000,
  'title': 'title not found',
  'mal_id': 'id not found',
  'url': 'url not found'},
 {'call_id': 5001,
  'title': 'title not found',
  'mal_id': 'id not found',
  'url': 'url not found'},
 {'call_id': 5002,
  'title': 'Bari Bari Densetsu',
  'mal_id': 5002,
  'url': 'https://myanimelist.net/anime/5002/Bari_Bari_Densetsu'}]

代码未按预期运行。我怎样才能得到想要的结果?

因为已经有一个循环来生成所有相同的 'call_id'in range(5000,5020) - 为了首先进行 API 调用 - 一个简单的方法是直接在第一个循环中创建最终数据,而不是存储 json_data 结果并尝试在以后的循环中处理它们。看起来像:

anime_data = []
for x in range(5000,5020):
    page_url = f'https://api.jikan.moe/v4/anime/{x}/full'
    response = requests.get(page_url)
    json_data = json.loads(response.text)
    anime = {
        'call_id': x,
        'title': json_data.get('data',{}).get('title','title not found'),
        'mal_id': json_data.get('data',{}).get('mal_id', 'id not found'),
        'url': json_data.get('data',{}).get('url', 'url not found')
    }
    anime_data.append(anime)
    time.sleep(1)

我们可以更好地组织逻辑,方法是 使用函数 拆分每次循环执行的任务,并通过 pre-computing .get('data',{}) 结果:

def query_api(anime_id):
    page_url = f'https://api.jikan.moe/v4/anime/{anime_id}/full'
    response = requests.get(page_url)
    return json.loads(response.text).get('data',{})

def make_anime_data(anime_id, raw_data):
    return {
        'call_id': anime_id,
        'title': raw_data.get('title','title not found'),
        'mal_id': raw_data.get('mal_id', 'id not found'),
        'url': raw_data.get('url', 'url not found')
    }

anime_data = []
for x in range(5000,5020):
    raw_data = query_api(x)
    anime_data.append(make_anime_data(x, raw_data))
    time.sleep(1)

解决问题的另一种方法:从根本上说,我们想要 iterate over two lists in parallel - 原始 API 响应,以及我们想要在其中使用的数字(来自 rangeanime 个条目。所以,天真的反应是使用 zip,因此:

for call_id, dic in zip(range(5000, 5020), test):
    anime = {
        'call_id': call_id,
        'title': dic.get('data',{}).get('title','title not found'),
        'mal_id': dic.get('data',{}).get('mal_id', 'id not found'),
        'url': dic.get('data',{}).get('url', 'url not found')
    }
    anime_data.append(anime)

但是,这忽略了一个更具体的 built-in 工具:built-in enumerate 函数。我们只需要适当地设置 start 点;我们不需要担心有多少元素 - 它会一直增加直到我们 运行 出来。

看起来像:

for call_id, dic in enumerate(test, 5000):
    anime = {
        'call_id': call_id,
        'title': dic.get('data',{}).get('title','title not found'),
        'mal_id': dic.get('data',{}).get('mal_id', 'id not found'),
        'url': dic.get('data',{}).get('url', 'url not found')
    }
    anime_data.append(anime)