Pandas DataFrame通过for循环追加数据失效问题求助
问题:循环追加数据后Pandas DataFrame始终为空的原因与解决办法
你遇到的是Pandas使用中非常典型的误区——代码里的modified_schemadf.append(...)看似在往DataFrame里加数据,但实际上根本没改变原对象,这是由append方法的特性直接导致的。
核心原因
Pandas的DataFrame.append()是无状态方法:它不会直接修改调用它的原DataFrame,而是返回一个包含追加后数据的新DataFrame对象。你的代码里只是调用了append,但没有把返回的新对象重新赋值给modified_schemadf,所以初始的空DataFrame一直没被更新,最后打印自然还是空的。
快速修复方案
把循环里的append语句改成赋值形式,让modified_schemadf指向追加后的新对象:
modified_schemadf = modified_schemadf.append(redshift_to_pandas("select '"+all_schema[i]+"' as columns_name,(select exists ( select distinct table_schema from information_schema.tables where table_schema like '%"+all_schema[i]+"')) as status",mechanism='append'))
不过要注意:从Pandas 2.0版本开始,append方法已经被标记为弃用,官方更推荐使用pd.concat()来实现数据合并,所以下面的优化方案更值得采用。
更优的实现方式(推荐)
频繁调用append会产生大量临时DataFrame,效率较低。建议先把每次查询得到的小DataFrame收集到列表里,最后一次性合并:
def redshift_to_pandas(sql_query,**kwargs): # pass a sql query and return a pandas dataframe cur.execute(sql_query) columns_list = [desc[0] for desc in cur.description] data = pd.DataFrame(cur.fetchall(),columns=columns_list) return data # Input:这里优化一下,[('backup')]其实等价于['backup'],如果要定义元组元素应该写成[('backup',)] all_schema = ['backup'] # Loop try: if len(all_schema) == 0: raise inputError("The Input has no schema selected. EXITING") else: # 初始化列表存储所有子DataFrame df_list = [] for schema in all_schema: # 用f-string简化字符串拼接(后续建议替换为参数化查询) df = redshift_to_pandas(f"select '{schema}' as columns_name,(select exists ( select distinct table_schema from information_schema.tables where table_schema like '%{schema}%')) as status",mechanism='append') df_list.append(df) # 一次性合并所有子DataFrame,ignore_index重置索引避免重复 modified_schemadf = pd.concat(df_list, ignore_index=True) print(modified_schemadf) except inputError as e: print(e.message) logger.error("UNEXPECTED INPUT FOUND, Please check the I/P List . EXITING") print(modified_schemadf)
额外优化建议
- 避免SQL字符串拼接:直接把变量拼到SQL语句里存在SQL注入风险,建议使用参数化查询。如果你的Redshift连接用的是psycopg2,可以修改函数支持参数:
def redshift_to_pandas(sql_query, params=None, **kwargs): cur.execute(sql_query, params or ()) columns_list = [desc[0] for desc in cur.description] data = pd.DataFrame(cur.fetchall(),columns=columns_list) return data # 调用时传入参数 df = redshift_to_pandas( "select %s as columns_name,(select exists ( select distinct table_schema from information_schema.tables where table_schema like %s)) as status", params=(schema, f"%{schema}%"), mechanism='append' )
- 批量查询代替循环:可以把所有schema一次性传入SQL,用批量查询替代循环调用,效率会更高:
# 生成schema的占位符 schema_strings = ','.join([f"'{s}'" for s in all_schema]) # 一次性查询所有schema的状态 sql = f""" select s.schema_name as columns_name, exists (select 1 from information_schema.tables where table_schema like '%' || s.schema_name || '%') as status from (values {schema_strings}) as s(schema_name) """ modified_schemadf = redshift_to_pandas(sql, mechanism='append')
这样不需要循环,一次查询就能得到所有结果,代码更简洁,性能也更好。
内容的提问来源于stack exchange,提问作者Golokesh Patra
相关产品推荐
相关产品推荐

