記一次程式設計及KeyError錯誤
阿新 • • 發佈:2021-08-16
程式功能的闡述,定義read_json()函式,將json格式檔案固定的物件讀入到程式中。以便後期對資料利用生成pandas的DataFrame物件,完成結構化資料的分列儲存。
1 import os,sys 2 from functools import reduce 3 import pandas as pd 4 import json 5 6 ENCODE = "utf8" 7 CWD_PATH = os.path.dirname(sys.argv[0]) 8 9 10 def func(i): 11 m,n = os.path.splitext(i)View Code12 if n == ".json": 13 return i 14 #載入JSON資料 15 def read_json(PATH): 16 lst = os.listdir(PATH) 17 lstt = list(map(lambda x:os.path.join(PATH, x), lst)) 18 lsf = list(filter(lambda x:os.path.isfile(x), lstt)) 19 lsj = list(filter(func,lsf)) 20 print(lsj) 21 iflen(lsj) == 1: 22 for f in lsj: 23 with open(f,'r',encoding=ENCODE) as jsonfile: 24 DL = json.load(jsonfile) 25 jsonfile.close() 26 else: 27 raise ValueError 28 return DL 29 30 #載入檔案 31 def get_file(dirpath,file_ls): 32 slogn = 033 if not os.path.exists(dirpath): #如果檔案不存在,輸出錯誤 34 print("目錄不存在,請確認!!!") 35 return file_ls, slogn 36 elif os.path.isfile(dirpath): 37 file_ls.append(dirpath) 38 slogn = 1 39 return file_ls, slogn 40 else: 41 file_t_ls = os.listdir(dirpath) 42 for file_item in file_t_ls: 43 file_p = dirpath + "\\" + file_item 44 if os.path.isfile(file_p): 45 i,j = os.path.splitext(file_p) 46 if j == ".txt"or j == ".TXT": 47 file_ls.append(file_p) 48 print("檔案路徑已載入完畢...") 49 return file_ls, slogn 50 51 #轉換列名為對應地類名稱 52 def convent_col(dict_1, index_name, DL): 53 print('***檔案處理中***') 54 df = pd.DataFrame(dict_1,index=index_name) 55 map_columns = DL["DLMC"] 56 df.rename(columns=map_columns, inplace=True) 57 df['合計']=df.sum(axis=1, numeric_only=True) 58 #print(df) 59 data = df.groupby('權屬單位').agg('sum') 60 return data 61 62 #生成表格 63 def deal_file(file_ls, dir_path): 64 if len(file_ls) == 0: 65 print("所選擇的路徑名為空") 66 return 'error' 67 else: 68 print("總共{}個檔案".format(len(file_ls))) 69 for file_item in file_ls: 70 #將檔名字作為首列索引(index_col) 71 base_name = os.path.basename(file_item) 72 #定義一個預設的值為列表的字典可以方便後期轉化為DataFream二維表,以便向其中新增資料(地類模板) 73 DL = read_json(CWD_PATH) 74 tmp_dict = DL['DLBM'] #defaultdict(list) 75 with open(file_item, 'r', encoding=ENCODE) as file: 76 for line in file: 77 if '@' in line: 78 tmp_ls = line.strip().split(',') 79 area = tmp_ls[1] #地類面積 80 qs = tmp_ls[4] #地類權屬 81 dlbm = tmp_ls[3] #地類編碼 82 tmp_dict["權屬"].append(qs) 83 if isinstance(tmp_dict.get(str(dlbm)),list): 84 tmp_dict[dlbm.strip()].append(float(area)) #座標檔案中出現的地類編碼都會建立一個鍵值對,鍵為地類編碼,值為面積列表 85 count = len(tmp_dict.get("權屬")) 86 for v in tmp_dict.values(): 87 if len(v) == count: 88 continue 89 else: 90 v.append(0.0) 91 else: 92 print(str(dlbm)) 93 print(tmp_dict) 94 del_key_ls = [] 95 for key,value in tmp_dict.items(): 96 sum = reduce(lambda x, y : x + y, value) 97 if sum == 0: 98 del_key_ls.append(key) 99 for i in del_key_ls: 100 tmp_dict.pop(i) 101 index_name = tmp_dict["權屬"] 102 data = convent_col(tmp_dict, index_name, DL) 103 #print(data) 104 save_single_data(data, dir_path, base_name) 105 106 #儲存表格 107 def save_single_data(data, s_path, name): 108 print('***檔案正在儲存***') 109 save_path = s_path + '\\' + name + '.xlsx' 110 data.to_excel(save_path,sheet_name='S_FLB',float_format='%.4f') 111 print('DataFrame is written successfully to the Excel File.') 112 113 #主程式 114 def main_app(dirpath): 115 file_ls = [] 116 f_ls, s = get_file(dirpath,file_ls) 117 if s: 118 dirpath = os.path.dirname(dirpath) 119 deal_file(f_ls, dirpath) 120 return "生成地類分類報表成功" 121 122 if __name__ == "__main__": 123 dirpath = input("請輸入要處理的檔案路徑:") 124 main_app(dirpath)
由於二維表資料列名(地類編碼)是固定的,之前是寫死在處理程式中,考慮到功能設計上的專一,將這部分寫死的資料改存到json檔案中讀取利用。
KeyError發生的位置
由於之前對程式功能考慮疏忽,在資料處理前期即讀取了json物件,導致後面程式處理空值列資料時將一些資料改動了,(python程式中要注意可變資料的引用)到迴圈遍歷階段,迴圈讀取到第二個座標檔案時,報出了KeyError錯誤,找不到Key。(原因:在第一個座標檔案處理時,將空列刪除了,導致了KeyError)
改變,將readjson()函式放入到迴圈遍歷座標物件下面,每次讀取一個檔案物件時,重新讀取json檔案,重新建立空值的DL物件。
注意點:在python程式中對可變資料物件使用時,一定要謹慎,因為它不會在一開始就丟擲錯誤,但在之後又要用到此物件時可能會產生意想不到的問題。