为何for循环会异常覆盖Python字典内容?
问题:Pandas转JSON时所有月份数据被最后一个月覆盖
尝试将Pandas DataFrame转换为JSON格式,先转Python字典再转JSON,但出现异常:所有月份的数据都被最后一次循环的月份数据覆盖。调试时数据处理顺序正确,但最终JSON输出不符合预期。
可复现代码
主文件代码:
import re import pandas as pd import json from help import Model # 引入另一个文件help.py jan = {'Month': ["January", "January", "January", "January"], 'Date': ['1st', '2nd', '28th', '29th'], 'a': ["j1a", "a3x", "d9c", "h9c"], 'b': ["X1", "SG", "DV", "XP"]} dec = {'Month': ["December", "December", "December", "December"], 'Date': ['1st', '2nd', '28th', '29th'], 'a': ["d1a", "o3x", "j9c", "h9c"], 'b': ["X2", "SG", "DV", "XP"]} a = pd.DataFrame.from_dict(jan) b = pd.DataFrame.from_dict(dec) dfs = [a, b] df = pd.concat(dfs) DateNum = [] for values in df['Date']: DateNum.append(re.search(r'\d+', values).group()) df['Date Num'] = DateNum df.reset_index(drop=True, inplace=True) dfl = df.Month.tolist() months = [] for data in dfl: if data not in months: months.append(data) # months = ['January', 'December'] models = [] for month in months: models.append(Model(month)) calendar = {} for month in models: datacopy = df.copy() datacopy = datacopy[datacopy.Month == month.name] month.data = datacopy month.update(debug=True) calendar[month.name] = month.days print(json.dumps(calendar, indent=4))
help.py文件代码:
class Model: """ model for months """ name = "" data = None days = {} def __init__(self, monthname): self.name = monthname def update(self, debug=False): edit = self.data # a copy of a slice from the df edit = edit.drop("Month", axis=1) # drop Month column edit = edit.set_index('Date Num').T.to_dict('list') # set Date Num column to be the index and make dict data_formatted = {self.name: edit} # save the dict with key as month name as data_formatted for k, v in data_formatted[self.name].items(): # data_formatted [month] = (day number : data) if debug: print(k, v) # e.g. k=1 v=['1st', 'a', 'n'] day_object = Day(v) # make a day object out of the values (formatting in initializer) self.days[k] = day_object.data_formatted # assign the formatted value e.g. days[1] = (formatted data) # print(self.days[k]) # shows correct data e.g. {'date': '25th', 'a': 'a', 'b': 'n', 'c': 'x'} class Day: date = "" a = "" b = "" data_formatted = {} def __init__(self, data): self.date = data[0] self.a = data[1] self.b = data[2] self.format_data() def format_data(self): self.data_formatted = { "date": self.date, "a": self.a, "b": self.b, }
调试输出(正常)
1 ['1st', 'j1a', 'X1'] 2 ['2nd', 'a3x', 'SG'] 28 ['28th', 'd9c', 'DV'] 29 ['29th', 'h9c', 'XP'] 1 ['1st', 'd1a', 'X2'] 2 ['2nd', 'o3x', 'SG'] 28 ['28th', 'j9c', 'DV'] 29 ['29th', 'h9c', 'XP']
异常JSON输出
{ "January": { "1": { "date": "1st", "a": "d1a", // 应为j1a "b": "X2" // 应为X1 }, "2": { "date": "2nd", "a": "o3x", // 应为a3x "b": "SG" } ... }
原因分析
问题出在类变量与实例变量的混淆:
Model类中的days = {}是类变量,所有Model实例会共享同一个字典对象。当第二个Model实例(December)更新days时,会直接覆盖第一个实例(January)的days内容,因为它们指向同一个内存地址。Day类中的data_formatted = {}同样是类变量,但在__init__中用self.data_formatted重新赋值为实例变量,所以这部分没有引发问题,但为了规范建议统一改为实例变量。
解决方案
将Model类中的days从类变量改为实例变量,在__init__方法中初始化;同时清理Day类中的冗余类变量:
修改后的help.py代码:
class Model: """ model for months """ def __init__(self, monthname): self.name = monthname self.data = None self.days = {} # 改为实例变量,每个实例独立拥有 def update(self, debug=False): edit = self.data.drop("Month", axis=1) edit = edit.set_index('Date Num').T.to_dict('list') for k, v in edit.items(): if debug: print(k, v) day_object = Day(v) self.days[k] = day_object.data_formatted class Day: def __init__(self, data): self.date = data[0] self.a = data[1] self.b = data[2] self.data_formatted = {} # 初始化实例变量 self.format_data() def format_data(self): self.data_formatted = { "date": self.date, "a": self.a, "b": self.b, }
修复后输出
运行主文件后,JSON输出将符合预期:
{ "January": { "1": { "date": "1st", "a": "j1a", "b": "X1" }, "2": { "date": "2nd", "a": "a3x", "b": "SG" }, "28": { "date": "28th", "a": "d9c", "b": "DV" }, "29": { "date": "29th", "a": "h9c", "b": "XP" } }, "December": { "1": { "date": "1st", "a": "d1a", "b": "X2" }, "2": { "date": "2nd", "a": "o3x", "b": "SG" }, "28": { "date": "28th", "a": "j9c", "b": "DV" }, "29": { "date": "29th", "a": "h9c", "b": "XP" } } }
内容的提问来源于stack exchange,提问作者mfm
相关产品推荐
相关产品推荐

