如何在遍历字典/列表时为Pandas DataFrame添加对应request_id列?
解决DataFrame添加request_id列全部为最后一个值的问题
这个问题我之前也碰到过!本质上是循环中变量引用或者DataFrame对象复用导致的,要么是你在循环里没有为每个请求创建独立的DataFrame,要么是变量的延迟绑定让所有df都指向了最后一次循环的request_id值。
先看正确的实现代码
假设我们有一个模拟的API调用函数call_api,核心是在每次循环中:
- 取出当前请求的
request_id和参数 - 调用API获取结果
- 把结果转为全新的DataFrame
- 为这个新df添加
request_id列(用当前循环的request_id值) - 将df追加到
responses列表
import pandas as pd # 模拟API调用函数,实际替换成你的真实API调用 def call_api(name): # 假设API返回这样的结构 return [{'product': f"{name}_item1"}, {'product': f"{name}_item2"}] dict_example = { 'Request_1': { 'request_id' : '1', 'name' : 'Foo' }, 'Request_2': { 'request_id' : '2', 'name' : 'Bar' }, 'Request_3': { 'request_id' : '3', 'name' : 'Barbie' } } responses = [] # 正确的遍历方式 for req_info in dict_example.values(): current_request_id = req_info['request_id'] current_name = req_info['name'] # 调用API获取数据 api_response = call_api(current_name) # 将API结果转为新的DataFrame df = pd.DataFrame(api_response) # 为当前df添加request_id列,用当前循环的request_id值 df['request_id'] = current_request_id # 将新的df加入列表 responses.append(df) # 验证结果 for idx, df in enumerate(responses): print(f"第{idx+1}个DataFrame的request_id列:") print(df['request_id'].unique())
为什么你的代码会出现所有request_id都是3?
最常见的两种原因:
- 复用同一个DataFrame对象:如果在循环外先定义了一个df,然后每次循环只是修改这个df的内容再append到列表,由于列表存储的是对象引用,最后所有列表项都会指向最后一次修改后的df,自然所有request_id都是最后一个值。
典型错误示例(如果是修改现有df而非创建新df):responses = [] df = pd.DataFrame(columns=['product', 'request_id']) # 循环外定义的固定df for req_info in dict_example.values(): current_request_id = req_info['request_id'] api_response = call_api(req_info['name']) df = pd.DataFrame(api_response) df['request_id'] = current_request_id responses.append(df) # 若此处是修改原有df而非重新赋值,就会导致引用问题 - 异步场景下的闭包延迟绑定:如果你的API调用是异步的(比如用
asyncio),在创建任务时使用闭包引用request_id,Python的闭包是延迟绑定的,所有任务会在循环结束后才去取request_id的值,也就是最后一个值3。
错误示例:
解决异步场景的问题,可以用默认参数绑定当前值:import asyncio async def async_call_api(name): await asyncio.sleep(0.1) return [{'product': f"{name}_item1"}] responses = [] async def main(): tasks = [] for req_info in dict_example.values(): request_id = req_info['request_id'] # 错误:闭包延迟绑定,所有任务都会用最后一个request_id task = asyncio.create_task( pd.DataFrame(await async_call_api(req_info['name'])).assign(request_id=request_id) ) tasks.append(task) responses.extend(await asyncio.gather(*tasks))task = asyncio.create_task( (lambda rid=request_id: pd.DataFrame(await async_call_api(req_info['name'])).assign(request_id=rid))() )
额外优化建议
- 如果API返回的数据结构一致,可以最后把所有df合并成一个大的DataFrame,方便后续处理:
combined_df = pd.concat(responses, ignore_index=True) - 可以用列表推导式简化代码(确保每次创建新df):
responses = [ pd.DataFrame(call_api(req['name'])).assign(request_id=req['request_id']) for req in dict_example.values() ]
内容的提问来源于stack exchange,提问作者Anna
相关产品推荐
相关产品推荐

