分享代码前,先作几点说明:
1.关于污染物浓度数据有效性的判断
对于整数,采用isdecimal()方法判断;对于小数(仅一氧化碳),采用split(‘.’)方法将字符串拆成两部分判断。
2.关于IAQI的计算
查阅资料,大多通过定义各污染物IAQI函数,然后elif分浓度区间计算。其实大可不必,因即使污染物不同、浓度范围不同,IAQI计算原理都是一样的:已知两个端点横纵坐标和未知点横坐标,利用相似三角形相似比性质,求未知点纵坐标。在这里,我们只要确定是什么污染物,处在什么浓度区间,定义一个函数通过两层遍历就可以解决。
3.关于开发环境
Python==3.4.4
pywin32==221.win32-py3.4
pyinstaller==3.2.1
选择以上开发环境,打包后的软件在XP平台也能运行
4.关于打包
推荐ToYcon制作多帧图标,pipenv虚拟环境打包
打包命令:pyinstaller -i *.ico -F -w *.py --upx-dir "upx主程序所在路径"
注意:因upx压缩后会加壳,杀软有报毒几率,慎用之
简易实现代码分享如下:
from math import ceil #导入进位取整函数
from collections import OrderedDict #导入有序字典模块(Python3.6以下字典无序)
#定义包含污染物名称、浓度区间和IAQI区间的有序字典
mapping = OrderedDict([
('PM2.5', ((0,0),(35,50),(75,100),(115,150),(150,200),(250,300),
(350,400),(500,500))),
('PM10', ((0,0),(50,50),(150,100),(250,150),(350,200),(420,300),
(500,400),(600,500))),
('臭氧', ((0,0),(100,50),(160,100),(215,150),(265,200),(800,300),
(1000,400),(1200,500))),
('一氧化碳', ((0,0),(2,50),(4,100),(14,150),(24,200),(36,300),
(48,400),(60,500))),
('二氧化氮', ((0,0),(40,50),(80,100),(180,150),(280,200),(565,300),
(750,400),(940,500))),
('二氧化硫', ((0,0),(50,50),(150,100),(475,150),(800,200), (1600,300),
(2100,400),(2620,500)))
])
def data_validity(pollutants):
"""判断数据有效性"""
for k, v in pollutants.items():
if not v:
pollutants[k] = '0' #空白初始化为0
elif not v.isdecimal():
if k != '一氧化碳': #因CO可保留3位以下小数,需单独判断
return False
num = v.split('.') #以小数点为分割符切成两部分来判断
if len(num) != 2 or (not num[0].isdecimal()) or (not num[1].isdecimal()) or len(num[1]) > 3:
return False
if float(pollutants[k]) > mapping[k][-1][0]: #超过限值情况
return False
else: #正常循环退出
return True
def iaqi_calc(pollutants):
"""计算各污染物IAQI"""
for k, v in mapping.items(): #遍历字典,确定污染物名称
for i in range(len(v)-1): #遍历嵌套元组,确定污染物浓度所处区间
if float(pollutants[k]) <= v[i+1][0]: #利用相似三角形相似比求值
iaqi = ceil((float(pollutants[k])-v[i][0])*(v[i+1][1]-v[i][1])/(v[i+1][0]-v[i][0]))+v[i][1]
pollutants[k] = iaqi #更新污染物浓度为IAQI
break #计算完毕,需及时跳出(为什么^-^)
for k, v in pollutants.items():
print("{}-IAQI:{}".format(k, v))
def aqi_calc(pollutants):
"""计算AQI及相关信息"""
aqi = max(pollutants.values())
if aqi > 50: #首要污染物
prime_pollutants = '、'.join(k for k, v in pollutants.items() if v == aqi)
else:
prime_pollutants = '无'
if aqi > 100: #超标污染物
exceed_pollutants = '、'.join(k for k, v in pollutants.items() if v > 100)
else:
exceed_pollutants = '无'
print("AQI:{}".format(aqi))
print("首要污染物:{}".format(prime_pollutants))
print("超标污染物:{}".format(exceed_pollutants))
def main():
"""主程序"""
while True:
#定义临时存放各污染物浓度和IAQI数值的有序字典
pollutants = OrderedDict([(k, input('请输入{}浓度:'.format(k))) for k in mapping])
if data_validity(pollutants):
print("-"*50)
iaqi_calc(pollutants)
print("-"*50)
aqi_calc(pollutants)
print("-"*50)
if input("如需终止计算,请输入q后回车:").lower() == 'q':
break
print("-"*50)
else:
print("-"*50)
print("数据无效,请重新输入!")
print("-"*50)
if __name__ == '__main__':
main()