一、练习要求
- 从网上找到中国省市区的json或字典数据
- 一、二、三级菜单分别对应省市区,且每个都有单独的代码
- 省、市菜单有输入对应代码进入下一级功能
- 有返回上一级功能和退出机制
二、练习分析
2.1 获取源数据
-
全国省市区json——来源于csdb,复制数据并另存为json格式。(最好在复制后去在线json检测网站检查是否valid)
-
最新县及县以上行政区划代码——来源于统计局,复制成文本格式,后期再通过python来解析txt获取并组成{(代码,省):{(代码,市):{(代码,区)}}}
-
直接通过统计局的网站,通过抓取来生成json文件(这个麻烦一些)
2.2 步骤分析
- 用函数来实现模块很方便,新手练习还是逐层实现
- 进入程序,显示省的名字和对应数字列表,以三列的形式来显示
- 提示输入省级代码,输入正确则进入对应市级列表;输入非法则提示重新输入;提示输入‘q’来退出程序(用break循环)
- 市级进到县级同上;另外,提示输入‘r’来返回上一级
- 县级界面,提示输入‘r’来返回上一级,‘q’来退出程序
- 设立标志位,整体用while来循环
三、代码实现
- 以json方法来实现最为快捷
- json文件命名为“City_json.json ”
-
下面是版本一:
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
'''China province to city, to district'''
__author__:'Wu HH'
# 导入json文件
import json
filename = 'City_json.json'
with open(filename, 'r') as file:
china_data = json.load(file)
# 打印省级的函数
def print_pro():
count = 0
for i in range(len(china_data)):
count += 1
print(china_data[i]['name'].ljust(8,'>'),'%02d'.ljust(6,' ') % i, end='')
# 用于打印成3列
if count % 3 == 0:
print('')
# 打印市级的函数
def print_city(city_num):
count = 0
for i in range(len(china_data[city_num]['city'])):
count += 1
print(china_data[city_num]['city'][i]['name'].ljust(8,'>'),'%02d'.ljust(6,' ') % i, end='')
# 用于打印成3列
if count % 3 == 0:
print('')
# 打印县级的函数
def print_area(city_num, area_num):
count = 0
for i in range(len(china_data[city_num]['city'][area_num]['area'])):
count += 1
print(china_data[city_num]['city'][area_num]['area'][i].ljust(8,'>'),'%02d'.ljust(6,' ') % i, end='')
# 用于打印成3列
if count % 3 == 0:
print('')
# 定位标志
loca_num = 0
while True:
# 打印省级
if loca_num == 0:
print_pro()
loca_num = 1
if loca_num == 1:
# 提示输入省级编号进入市级,并提示q退出
into_city_num = input('Please input number to get into city. "q" to quit. ')
if into_city_num == 'q':
break
elif int(into_city_num) > 0 and int(into_city_num) <= len(china_data):
into_city_num = int(into_city_num)
if loca_num == 1:
print_city(into_city_num)
loca_num = 2
else:
print('please input a valid number')
if loca_num == 2:
# 提示输入市级编号进入县级,并提示q退出,r返回上一级
into_area_num = input('Please input number to get into city. "q" to quit. "r" to return. ')
if into_area_num == 'q':
break
elif into_area_num == 'r':
loca_num = 0
continue
elif int(into_area_num) > 0 and int(into_area_num) <= len(china_data[into_city_num]['city']):
into_area_num = int(into_area_num)
if loca_num == 2:
print_area(into_city_num, into_area_num)
loca_num = 3
else:
print('please input a valid number')
if loca_num == 3:
# 提示q退出,r返回上一级
input_in_area = input('"q" to quit. "r" to return. ')
if input_in_area == 'q':
break
elif input_in_area == 'r':
loca_num = 2
print_city(into_city_num)
continue
else:
print("please input a 'q' or 'r'")
-
下面是优化版本二:(网上找的博客园-金角大王)
- 很佩服这个版本,但是交互是通过输入完成城市名而不是数字
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
'''more elegent version of China province program'''
__author__:'Wu HH'
# 导入json文件
import json
filename = 'City_json.json'
with open(filename, 'r') as file:
china_data = json.load(file)
# 重组json成层叠字典{a:{b1:{c1:[]},c2:{}},b2:{...}...}
china_data_dic = {}
for province_total in china_data:
city_temp = {}
for city_total in province_total['city']:
city_temp[city_total['name']] = city_total['area']
china_data_dic[province_total['name']] = city_temp
exit_active = False
current_class = china_data_dic
parent_classes = [china_data_dic]
while not exit_active:
count_num = 0
for k in current_class:
count_num += 1
print(k.ljust(8, ' '),end='')
if count_num % 3 == 0:
print('')
choice = input(">>:").strip()
if choice == 'b' and parent_classes != []:
current_class = parent_classes[-1]
parent_classes.pop()
elif choice == 'q':
exit_active = True
elif choice not in current_class:
continue
else:
if current_class not in parent_classes:
parent_classes.append(current_class)
try:
current_class = current_class[choice]
except TypeError:
continue
思考了好一会儿都没想到怎么解决“县级在非合法输入后,需要‘b’两次才能返回市级”的bug。先留着,以后有空继续思考
网友评论