环境变量读取失败?,90%的人都忽略了os.environ的这3个转换细节

os.environ环境变量转换避坑指南

第一章:环境变量读取失败?你可能忽略了os.environ的本质

在Python开发中,通过 os.environ 读取环境变量是常见操作,但许多开发者遇到“变量未生效”或“值为空”的问题,往往是因为误解了 os.environ 的本质。它并非一个普通字典,而是对操作系统环境变量的动态映射,其行为受进程启动时环境快照的影响。

理解 os.environ 的底层机制

os.environ 是一个 os._Environ 对象,封装了程序启动时刻的操作系统环境。一旦进程运行,它不会自动感知外部环境的变化。例如,在 shell 中修改 export API_KEY=new_value 后,已运行的 Python 进程仍保留旧值。

正确读取环境变量的方法

推荐使用 os.getenv() 而非直接访问 os.environ,因为它更安全且支持默认值:
# 推荐方式:使用 getenv 避免 KeyError
import os

api_key = os.getenv('API_KEY', 'default_value')
if not api_key:
    print("警告:API_KEY 为空")

调试环境变量的实用策略

当变量读取异常时,可列出所有当前可见的环境变量进行排查:
import os

for key, value in os.environ.items():
    print(f"{key}={value}")
  • 确保环境变量在进程启动前已设置(如在 .bashrc 或 systemd 配置中)
  • 容器化部署时检查 Dockerfile 或 Kubernetes ConfigMap 是否正确注入
  • 避免在代码中硬编码敏感信息,始终优先使用环境变量
方法是否抛出 KeyError支持默认值
os.environ['KEY']
os.getenv('KEY')

第二章:字符串到数值类型的转换陷阱与解决方案

2.1 os.environ默认返回字符串:理论机制解析

Python 的 os.environ 是对操作系统环境变量的映射接口,其底层依赖于 C 语言级别的 getenv() 系统调用。所有环境变量在操作系统中均以字符串形式存储,因此无论原始意图是数字还是布尔值,os.environ 返回的值始终为字符串类型。
典型行为示例
import os

os.environ['PORT'] = '8080'
port = os.environ['PORT']
print(type(port))  # <class 'str'>
上述代码中,即使 PORT 表示一个端口号,其值仍以字符串形式存储和返回。若需数值运算,必须显式转换,如 int(os.environ['PORT'])
类型转换风险表
环境变量期望类型转换方式
DEBUGboolos.environ.get('DEBUG').lower() == 'true'
RETRIESintint(os.environ['RETRIES'])

2.2 int转换实践:从环境变量解析端口号

在服务配置中,常通过环境变量获取端口号。由于环境变量以字符串形式存储,需将其安全转换为整型。
基础转换流程
使用标准库函数进行类型解析,确保异常处理完整:
portStr := os.Getenv("PORT")
if portStr == "" {
    portStr = "8080" // 默认值
}
port, err := strconv.Atoi(portStr)
if err != nil {
    log.Fatal("无效端口号:", portStr)
}
上述代码首先获取环境变量 PORT,若为空则使用默认值 8080。随后调用 strconv.Atoi 将字符串转为整数,失败时记录错误并终止程序。
常见端口对照表
服务类型推荐端口
HTTP80
HTTPS443
开发服务8080

2.3 float转换实战:配置参数中的精度处理

在系统配置中,浮点数常用于表示阈值、权重等敏感参数。不当的精度处理可能导致逻辑偏差。
典型应用场景
例如,在限流策略中使用浮点数控制QPS阈值:
threshold := 9.8765
rounded := math.Round(threshold*100) / 100 // 保留两位小数
fmt.Printf("Adjusted threshold: %.2f", rounded)
该代码通过放大、四舍五入再缩小的方式实现精度截断,确保配置值符合预期范围。
常见精度控制策略
  • 使用 math.Round(x * 1eN) / 1eN 实现指定小数位四舍五入
  • 通过 strconv.FormatFloat 进行字符串级精度格式化
  • 在配置解析阶段预设默认精度,避免运行时误差累积
合理控制float精度可提升系统稳定性和可预测性。

2.4 安全转换封装:避免ValueError的健壮函数设计

在数据处理过程中,类型转换是常见操作,但原始数据可能包含非法格式,直接转换易引发 ValueError。为提升代码鲁棒性,应封装安全转换函数,对异常进行捕获与处理。
安全整型转换示例
def safe_int(value, default=None):
    """
    安全地将值转换为整数
    :param value: 待转换的值
    :param default: 转换失败时返回的默认值
    :return: 转换后的整数或默认值
    """
    try:
        return int(float(value))  # 支持 "3.14" 类字符串
    except (ValueError, TypeError):
        return default
该函数通过嵌套转换支持浮点字符串,并捕获多种异常类型,确保调用方无需额外处理错误。
常用转换策略对比
方法安全性适用场景
int()已知合法输入
safe_int()外部数据源

2.5 类型验证与默认值策略:提升代码容错能力

在现代应用开发中,确保输入数据的合法性与完整性是构建稳定系统的关键。类型验证可防止非法数据进入业务逻辑层,而合理的默认值策略则能有效降低调用方使用成本。
类型验证机制
通过结构体标签(struct tag)结合反射机制,可在运行时校验字段类型与约束:

type User struct {
    Name string `validate:"required"`
    Age  int    `validate:"min=0,max=150"`
}
上述代码利用 validate 标签定义字段规则,配合验证库(如 validator.v9)实现自动校验,提升数据安全性。
默认值填充策略
使用默认值可避免因缺失配置导致的运行时错误:
  • 初始化时自动注入合理默认值
  • 支持环境变量覆盖,增强灵活性
  • 结合配置中心实现动态更新

第三章:布尔值与特殊类型的转换逻辑

3.1 布尔环境变量的是非之争:常见误区剖析

在配置管理系统中,布尔环境变量的解析常引发意料之外的行为。开发者普遍误认为非空字符串即代表“真”,然而多数解析库仅将特定值(如 `true`、`1`、`on`)视为真值。
典型错误用法示例
ENABLE_FEATURE="false"
if [ "$ENABLE_FEATURE" ]; then
  echo "Feature enabled"  # 错误:非空字符串始终为真
fi
上述代码逻辑错误地依赖字符串非空判断,而非语义化布尔解析。
推荐处理方式
  • 使用明确的值对比,如 [ "$ENABLE_FEATURE" = "true" ]
  • 借助配置库进行类型转换,避免手动解析
  • 在应用启动时预处理环境变量,统一归一化为标准布尔值
输入值预期布尔值
true, 1, yes, on✅ true
false, 0, no, off❌ false

3.2 实现可靠的字符串到bool转换函数

在开发中,将用户输入或配置项中的字符串安全地转换为布尔值是常见需求。直接解析时若不严谨,易引发运行时错误或逻辑漏洞。
常见布尔字符串表示
通常认为以下字符串应被解析为真值:
  • "true"、"True"、"TRUE"
  • "1"、"on"、"yes"(在特定上下文中)
而假值包括:"false"、"0"、"no"、"off" 等。
Go语言实现示例
func parseBool(s string) (bool, error) {
    switch strings.ToLower(s) {
    case "true", "1", "on", "yes":
        return true, nil
    case "false", "0", "off", "no":
        return false, nil
    default:
        return false, fmt.Errorf("invalid boolean string: %s", s)
    }
}
该函数对输入字符串统一转为小写后进行匹配,确保大小写不敏感;返回布尔值及错误信息,调用方能明确处理解析失败情况。
错误处理与健壮性
使用此函数时,必须检查返回的 error 值,避免忽略非法输入,从而提升系统鲁棒性。

3.3 None与空值处理:区分未设置与显式关闭

在配置系统中,None 常被误认为等同于“关闭”或“空字符串”,但实际上它代表“未设置”。正确区分 None 与显式关闭(如 False"")对配置解析至关重要。
语义差异示例
config = {
    'timeout': None,        # 未设置,应使用默认值
    'debug': False,         # 显式关闭
    'log_path': ""          # 显式设为空路径
}
上述代码中,timeoutNone 应触发默认超时机制,而 debug=False 明确禁用调试模式。
处理策略对比
含义处理方式
None未配置使用默认值
False显式关闭禁用功能
""空字符串保留但为空

第四章:复杂数据结构的反序列化技巧

4.1 JSON字符串还原:从环境变量加载列表与字典

在微服务与容器化部署中,常通过环境变量传递结构化配置。直接传递列表或字典需将其序列化为JSON字符串,在应用启动时反序列化还原。
JSON字符串的还原机制
使用标准库如Python的 json.loads() 可将环境变量中的JSON字符串转换为原生数据结构:
import os
import json

# 示例环境变量: '["dev", "test", "prod"]'
env_list = os.getenv("ALLOWED_ENVS", "[]")
allowed_envs = json.loads(env_list)

# 输出: ['dev', 'test', 'prod']
print(allowed_envs)
该代码从环境变量读取JSON格式字符串,json.loads() 解析后还原为Python列表。若变量缺失,默认返回空数组。
常见数据类型映射
环境变量值Python类型说明
{"debug": true}dict布尔值正确解析
[1, 2, 3]list整数数组还原

4.2 分隔符拆分法:解析逗号分隔的字符串为列表

在数据处理中,常需将逗号分隔的字符串转换为结构化列表。Python 提供了简单高效的内置方法实现这一操作。
基础拆分操作
使用 str.split() 方法可按指定分隔符切割字符串:

data = "apple,banana,grape"
fruits = data.split(',')
print(fruits)  # 输出: ['apple', 'banana', 'grape']
该方法默认以逗号为分隔符,返回一个包含子字符串的列表。注意空格可能影响结果,必要时可结合 strip() 预处理。
异常情况处理
  • 连续逗号可能导致空字符串项,如 "a,,b" 拆分为 ['a', '', 'b']
  • 建议使用列表推导式过滤空值:[x.strip() for x in data.split(',') if x.strip()]

4.3 时间间隔与大小单位解析:如"5s"、"1GB"的语义转换

在配置系统或编写程序时,时间间隔与数据大小常以人类可读的形式表示,如"5s"代表5秒,"1GB"表示1吉字节。这些字符串需被正确解析为数值以便程序处理。
常见单位映射表
类型符号含义换算值
时间s1
时间m分钟60
大小KB千字节1024
大小MB兆字节1048576
Go语言中的解析实现
package main

import (
    "fmt"
    "time"
)

func main() {
    duration, _ := time.ParseDuration("5s")
    fmt.Println(duration.Seconds()) // 输出: 5
}
该代码使用标准库time.ParseDuration将字符串"5s"解析为time.Duration类型,支持ns、us、ms、s、m、h等单位,自动完成语义转换。

4.4 自定义解析器设计:构建可复用的类型转换工具集

在复杂系统中,数据常以多种格式流转,如JSON、YAML或数据库原始值。为统一处理类型转换逻辑,需设计可复用的自定义解析器。
解析器核心接口设计
通过定义通用接口,确保各类解析器行为一致:
type Parser interface {
    Parse(input string) (interface{}, error)
    TargetType() reflect.Type
}
该接口要求实现 `Parse` 方法将字符串转为目标类型,并通过 `TargetType` 返回目标类型的反射类型,便于运行时匹配。
支持的类型映射表
使用表格明确内置支持的类型转换:
源类型目标类型示例
stringint"123" → 123
stringbool"true" → true
stringtime.Time"2025-04-05" → Time
组合式解析流程
ParseRequest → 格式识别 → 类型匹配 → 转换执行 → 结果封装

第五章:最佳实践总结与生产环境建议

配置管理的统一化
在生产环境中,保持配置一致性至关重要。推荐使用集中式配置管理工具,如 Consul 或 etcd,并通过环境变量注入敏感信息。以下为 Go 应用加载配置的示例:

type Config struct {
  DBHost string `env:"DB_HOST"`
  Port   int    `env:"PORT" envDefault:"8080"`
}

func LoadConfig() (*Config, error) {
  cfg := &Config{}
  if err := env.Parse(cfg); err != nil {
    return nil, err
  }
  return cfg, nil
}
日志与监控集成
结构化日志是排查问题的关键。建议使用 JSON 格式输出日志,并接入 ELK 或 Loki 进行集中分析。同时,关键服务应暴露 Prometheus 指标端点。
  • 所有错误日志必须包含 trace ID 和时间戳
  • 每分钟请求量、延迟 P99、错误率需可视化
  • 使用 OpenTelemetry 统一追踪链路
高可用部署策略
避免单点故障,确保服务跨可用区部署。Kubernetes 中应设置合理的资源限制与就绪探针:
参数建议值说明
replicas3+跨节点分布
readinessProbe.initialDelaySeconds10避免启动期间误杀
resources.limits.memory512Mi防止内存溢出影响节点
安全加固措施
所有生产服务应运行在非 root 用户下,网络策略限制仅允许必要端口通信。定期扫描镜像漏洞,使用最小基础镜像(如 distroless)构建容器。
我的python代码,配合CSH脚本(init.csh),能在linux环境下运行。但在windows调试中,os.environ.get("CSTHOME") 这样的语句无法运行起来,请分析怎样在windows中,也可以运行和调试 以下是init.csh代码 #!/bin/csh -f # # - initial config # ================================================================================================= # -- setup config if ( $4 == "" ) then /bin/echo -e "\033[33;1m >> ERROR : run with (csh $0 &#39;EX-CST&#39; &#39;CASE&#39; &#39;DATADT&#39; &#39;SITECODE&#39;)\033[0m" exit 1 endif # 接收4个参数 set PROJECT = $1 set RUNID = $2 set NEWDATE = $3 # 2025-09-25 set NEWID = $4 # 37080002 # 解析日期参数 set YEAR = `echo $NEWDATE | awk -F&#39;-&#39; &#39;{print $1}&#39;` set MONTH = `echo $NEWDATE | awk -F&#39;-&#39; &#39;{print $2}&#39;` set DAY = `echo $NEWDATE | awk -F&#39;-&#39; &#39;{print $3}&#39;` # ================================================================================================= # HOME [模型运行配置] setenv MODHOME "$HOME/pj2" # # config for model NAME and PATH setenv MODNAM "a2" setenv MODLAB "$MODHOME/$MODNAM" # model dirs setenv MODEXE "$MODLAB/exec" setenv MODSRC "$MODLAB/scripts" setenv MODTOL "$MODLAB/tools" setenv MODINI "$MODLAB/static" setenv CSTHOME "$MODLAB/result/$NEWDATE/$NEWID" setenv COMBINE "$CSTHOME/result" setenv BASECST "$CSTHOME/base/base/constraints" setenv BASEOUT "$CSTHOME/base/base/output" setenv MODRUNS "$CSTHOME/runs" setenv MODCFG "$MODRUNS/model/configuration" setenv MODMCM "$MODRUNS/mcm" setenv ENVFILE "$CSTHOME/envs" setenv DATANM "$MODLAB/data/$2.csv" setenv ALLMAP "$MODINI/variablesMapping.txt" set STEP_SIZE = 3600 set RATE_OUT_STEP_SIZE = 3600 set CONSTR = "$1" # -- if clear link files ? setenv CLEAN YES 以下是python文件代码: import sys import os import pandas as pd import numpy as np from datetime import timedelta import warnings warnings.filterwarnings("ignore", category=FutureWarning) def base_trans(df, maps): for key, value in maps.items(): if key in df.columns: if value not in [&#39;TEMP&#39;, &#39;PRESS&#39;, &#39;RH&#39;, &#39;J4&#39;, &#39;CO&#39;, &#39;NO&#39;, &#39;NO2&#39;]: df[key] = df[key] * 2.46 * 10 ** 10 # 取 Vm = 24.47 L/mol elif value == &#39;TEMP&#39;: df[key] = df[key] + 273.15 elif value == &#39;CO&#39;: df[key] = df[key] * 2.15 * 10 ** 13 elif value == &#39;NO&#39;: df[key] = df[key] * 2.01 * 10 ** 10 elif value == &#39;NO2&#39;: df[key] = df[key] * 1.31 * 10 ** 10 else: continue return df def rir_generator(df_total, df_maps): map_dict = df_maps.to_dict(orient=&#39;list&#39;) alkanes_list = df_maps[&#39;MCM&#39;][df_maps[&#39;CATEGORY&#39;] == &#39;烷烃&#39;].values.tolist() olefin_list = df_maps[&#39;MCM&#39;][df_maps[&#39;CATEGORY&#39;] == &#39;烯烃&#39;].values.tolist() alkyne_list = df_maps[&#39;MCM&#39;][df_maps[&#39;CATEGORY&#39;] == &#39;炔烃&#39;].values.tolist() aromatics_list = df_maps[&#39;MCM&#39;][df_maps[&#39;CATEGORY&#39;] == &#39;芳香烃&#39;].values.tolist() halogenated_hydrocarbon = df_maps[&#39;MCM&#39;][df_maps[&#39;CATEGORY&#39;] == &#39;卤代烃&#39;].values.tolist() ovocs = df_maps[&#39;MCM&#39;][df_maps[&#39;CATEGORY&#39;] == &#39;含氧&#39;].values.tolist() cat_dict = {&#39;AVOCs&#39;: [&#39;NO&#39;, &#39;NO2&#39;, &#39;CO&#39;, &#39;TEMP&#39;, &#39;PRESS&#39;, &#39;RH&#39;, &#39;J4&#39;, &#39;C5H8&#39;], &#39;BVOCs&#39;: [&#39;C5H8&#39;], &#39;NOx&#39;: [&#39;NO&#39;, &#39;NO2&#39;], &#39;CO&#39;: [&#39;CO&#39;], &#39;TEMP&#39;: [&#39;TEMP&#39;], &#39;RH&#39;: [&#39;RH&#39;], &#39;wt&#39;: alkanes_list, &#39;xt&#39;: olefin_list, &#39;qt&#39;: alkyne_list, &#39;fxt&#39;: aromatics_list, &#39;ldt&#39;: halogenated_hydrocarbon, &#39;OVOCs&#39;: ovocs } for minus, species in cat_dict.items(): path1 = os.path.join(os.environ.get("CSTHOME"), &#39;rir&#39; + os.sep + minus + &#39;_10%&#39; + os.sep) path = os.path.join(path1, &#39;constraints&#39;) out_path = os.path.join(path1, &#39;output&#39;) reac_path = os.path.join(out_path, &#39;reactionRates&#39;) spe_path = os.path.join(path, &#39;species&#39;) env_path = os.path.join(path, &#39;environment&#39;) pho_path = os.path.join(path, &#39;photolysis&#39;) os.makedirs(spe_path, exist_ok=True) os.makedirs(env_path, exist_ok=True) os.makedirs(pho_path, exist_ok=True) os.makedirs(reac_path, exist_ok=True) # AVOCs种类繁多,因此处理时取补集 if minus == &#39;AVOCs&#39;: for i in range(len(map_dict[&#39;MCM&#39;])): if map_dict[&#39;VARIABLE&#39;][i] in df_total.columns: if map_dict[&#39;MCM&#39;][i] not in species: df_total[map_dict[&#39;MCM&#39;][i]] = df_total[map_dict[&#39;VARIABLE&#39;][i]] * 0.9 df_total[[&#39;Time&#39;, map_dict[&#39;MCM&#39;][i]]].to_csv(os.path.join(spe_path, map_dict[&#39;MCM&#39;][i]), header=None, index=False, sep=&#39; &#39;) else: df_total[map_dict[&#39;MCM&#39;][i]] = df_total[map_dict[&#39;VARIABLE&#39;][i]] * 1.0 if map_dict[&#39;MCM&#39;][i] in [&#39;TEMP&#39;, &#39;PRESS&#39;, &#39;RH&#39;]: df_total[[&#39;Time&#39;, map_dict[&#39;MCM&#39;][i]]].to_csv(os.path.join(env_path, map_dict[&#39;MCM&#39;][i]), header=None, index=False, sep=&#39; &#39;) elif map_dict[&#39;MCM&#39;][i] in [&#39;J4&#39;]: df_total[[&#39;Time&#39;, map_dict[&#39;MCM&#39;][i]]].to_csv(os.path.join(pho_path, map_dict[&#39;MCM&#39;][i]), header=None, index=False, sep=&#39; &#39;) else: df_total[[&#39;Time&#39;, map_dict[&#39;MCM&#39;][i]]].to_csv(os.path.join(spe_path, map_dict[&#39;MCM&#39;][i]), header=None, index=False, sep=&#39; &#39;) else: for i in range(len(map_dict[&#39;MCM&#39;])): if map_dict[&#39;VARIABLE&#39;][i] in df_total.columns: if map_dict[&#39;MCM&#39;][i] in species: df_total[map_dict[&#39;MCM&#39;][i]] = df_total[map_dict[&#39;VARIABLE&#39;][i]] * 0.9 else: df_total[map_dict[&#39;MCM&#39;][i]] = df_total[map_dict[&#39;VARIABLE&#39;][i]] * 1.0 if map_dict[&#39;MCM&#39;][i] in [&#39;TEMP&#39;, &#39;PRESS&#39;, &#39;RH&#39;]: df_total[[&#39;Time&#39;, map_dict[&#39;MCM&#39;][i]]].to_csv(os.path.join(env_path, map_dict[&#39;MCM&#39;][i]), header=None, index=False, sep=&#39; &#39;) elif map_dict[&#39;MCM&#39;][i] in [&#39;J4&#39;]: df_total[[&#39;Time&#39;, map_dict[&#39;MCM&#39;][i]]].to_csv(os.path.join(pho_path, map_dict[&#39;MCM&#39;][i]), header=None, index=False, sep=&#39; &#39;) else: df_total[[&#39;Time&#39;, map_dict[&#39;MCM&#39;][i]]].to_csv(os.path.join(spe_path, map_dict[&#39;MCM&#39;][i]), header=None, index=False, sep=&#39; &#39;) def ekma_generator(df_total, map_dict): cat_dict = {&#39;AVOCs&#39;: [&#39;NO&#39;, &#39;NO2&#39;, &#39;CO&#39;, &#39;TEMP&#39;, &#39;PRESS&#39;, &#39;RH&#39;, &#39;J4&#39;, &#39;C5H8&#39;], &#39;NOx&#39;: [&#39;NO&#39;, &#39;NO2&#39;]} # for i_nox in [0.01, 0.05, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0, 1.2, 1.5, 2.0, 2.5, 3]: # for j_voc in [0.01, 0.05, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0, 1.2, 1.5, 2.0]: #for i_nox in [0.01, 0.1, 0.3, 0.5, 0.7, 0.9, 1.2, 2.0, 3]: # for j_voc in [0.01, 0.1, 0.3, 0.5, 0.7, 0.9, 1.2, 2.0]: for i_nox in [0.01, 0.1, 0.5, 1, 1.5,2.0,2.5, 3]: for j_voc in [0.01, 0.1, 0.5, 1,1.5, 2]: for minus, species in cat_dict.items(): path1 = os.path.join(os.environ.get("CSTHOME"), &#39;ekma&#39; + os.sep + &#39;NOx&#39; + str(round(i_nox * 100)) + &#39;%_&#39; + &#39;AVOCs&#39; + str(round(j_voc * 100)) + &#39;%&#39;) path = os.path.join(path1, &#39;constraints&#39;) spe_path = os.path.join(path, &#39;species&#39;) env_path = os.path.join(path, &#39;environment&#39;) pho_path = os.path.join(path, &#39;photolysis&#39;) out_path = os.path.join(path1, &#39;output&#39;) reac_path = os.path.join(out_path, &#39;reactionRates&#39;) os.makedirs(spe_path, exist_ok=True) os.makedirs(env_path, exist_ok=True) os.makedirs(pho_path, exist_ok=True) os.makedirs(reac_path, exist_ok=True) if minus == &#39;AVOCs&#39;: for i in range(len(map_dict[&#39;MCM&#39;])): if map_dict[&#39;VARIABLE&#39;][i] in df_total.columns: if map_dict[&#39;MCM&#39;][i] not in species: df_total[map_dict[&#39;MCM&#39;][i]] = df_total[map_dict[&#39;VARIABLE&#39;][i]] * j_voc elif map_dict[&#39;MCM&#39;][i] in [&#39;NO&#39;, &#39;NO2&#39;]: df_total[map_dict[&#39;MCM&#39;][i]] = df_total[map_dict[&#39;VARIABLE&#39;][i]] * i_nox else: df_total[map_dict[&#39;MCM&#39;][i]] = df_total[map_dict[&#39;VARIABLE&#39;][i]] * 1.0 if map_dict[&#39;MCM&#39;][i] in [&#39;TEMP&#39;, &#39;PRESS&#39;, &#39;RH&#39;]: df_total[[&#39;Time&#39;, map_dict[&#39;MCM&#39;][i]]].to_csv( os.path.join(env_path, map_dict[&#39;MCM&#39;][i]), header=None, index=False, sep=&#39; &#39;) elif map_dict[&#39;MCM&#39;][i] in [&#39;J4&#39;]: df_total[[&#39;Time&#39;, map_dict[&#39;MCM&#39;][i]]].to_csv( os.path.join(pho_path, map_dict[&#39;MCM&#39;][i]), header=None, index=False, sep=&#39; &#39;) else: df_total[[&#39;Time&#39;, map_dict[&#39;MCM&#39;][i]]].to_csv(os.path.join(spe_path, map_dict[&#39;MCM&#39;][i]), header=None, index=False, sep=&#39; &#39;) else: for i in range(len(map_dict[&#39;MCM&#39;])): if map_dict[&#39;VARIABLE&#39;][i] in df_total.columns: if map_dict[&#39;MCM&#39;][i] in species: df_total[map_dict[&#39;MCM&#39;][i]] = df_total[map_dict[&#39;VARIABLE&#39;][i]] * i_nox elif map_dict[&#39;MCM&#39;][i] not in [&#39;NO&#39;, &#39;NO2&#39;, &#39;CO&#39;, &#39;TEMP&#39;, &#39;PRESS&#39;, &#39;RH&#39;, &#39;J4&#39;, &#39;C5H8&#39;]: df_total[map_dict[&#39;MCM&#39;][i]] = df_total[map_dict[&#39;VARIABLE&#39;][i]] * j_voc else: df_total[map_dict[&#39;MCM&#39;][i]] = df_total[map_dict[&#39;VARIABLE&#39;][i]] * 1.0 if map_dict[&#39;MCM&#39;][i] in [&#39;TEMP&#39;, &#39;PRESS&#39;, &#39;RH&#39;]: df_total[[&#39;Time&#39;, map_dict[&#39;MCM&#39;][i]]].to_csv( os.path.join(env_path, map_dict[&#39;MCM&#39;][i]), header=None, index=False, sep=&#39; &#39;) elif map_dict[&#39;MCM&#39;][i] in [&#39;J4&#39;]: df_total[[&#39;Time&#39;, map_dict[&#39;MCM&#39;][i]]].to_csv( os.path.join(pho_path, map_dict[&#39;MCM&#39;][i]), header=None, index=False, sep=&#39; &#39;) else: df_total[[&#39;Time&#39;, map_dict[&#39;MCM&#39;][i]]].to_csv(os.path.join(spe_path, map_dict[&#39;MCM&#39;][i]), header=None, index=False, sep=&#39; &#39;) def main_process(data_file, map_file): suf = data_file.split(&#39;.&#39;)[-1] if suf == &#39;xls&#39; or suf == &#39;xlsx&#39;: df_origin = pd.read_excel(data_file) else: df_origin = pd.read_csv(data_file) df_map = pd.read_csv(map_file, sep="\\s+") map_dict = df_map.set_index([&#39;VARIABLE&#39;])[&#39;MCM&#39;].to_dict() # 转换数据类型 df_origin[df_origin.columns[5:]] = df_origin[df_origin.columns[5:]].apply(pd.to_numeric, errors=&#39;coerce&#39;) lim_nan = df_origin[df_origin.columns[5:]].apply(lambda x: x < 0) df_origin[lim_nan] = np.nan # 确保数据间隔时间为1小时 df_dr = pd.DataFrame(pd.date_range(start=df_origin[&#39;开始时间&#39;].values[0], end=df_origin[&#39;开始时间&#39;].values[-1], freq=&#39;h&#39;), columns=[&#39;Date&#39;]) # df_dr[&#39;Date&#39;] = df_dr[&#39;Date&#39;].apply(lambda x: (pd.to_datetime(str(x))).strftime(&#39;%Y/%m/%d %H:%M&#39;)) df_origin = df_origin.copy() df_origin[&#39;Date&#39;] = pd.to_datetime(df_origin[&#39;开始时间&#39;], format="%Y-%m-%d %H:%M:%S") df_origin = pd.merge(left=df_dr, right=df_origin, on=[&#39;Date&#39;], how=&#39;outer&#39;) # 对指定列进行插值 df_origin = df_origin.bfill() df_origin = df_origin.infer_objects(copy=False) # 先调用 infer_objects 方法 df_origin[df_origin.columns[5:]] = df_origin[df_origin.columns[5:]].infer_objects(copy=False) # 再进行插值操作 df_origin[df_origin.columns[5:]] = df_origin[df_origin.columns[5:]].interpolate(method=&#39;linear&#39;) # 部分特殊列的处理,原始数据必须包含这些列 df_origin[&#39;Date&#39;] = pd.to_datetime(df_origin[&#39;开始时间&#39;], format="%Y-%m-%d %H:%M:%S") # df_origin[&#39;BP(mbar)&#39;] = df_origin[&#39;BP(hPa)&#39;].values # 1mb = 1hPa df_origin = df_origin.copy() # df_origin[&#39;jNO2(s-1)&#39;] = df_origin[&#39;jNO2(E-10)&#39;] / 10000000000.0 # 新增多日数据平均到24日处理 df_origin = (df_origin.reset_index()).drop(&#39;index&#39;, axis=1) numeric_columns = df_origin.select_dtypes(include=[np.number]).columns df_numeric = df_origin[numeric_columns] df_origins = (df_numeric.groupby(df_origin[&#39;Date&#39;].dt.hour).mean()).drop(&#39;序号&#39;, axis=1, errors=&#39;ignore&#39;) df_origins = (df_origin.loc[df_origin.index[:24], df_origin.columns[:6]]).join(df_origins) df_origin = df_origins df_origin = df_origin.dropna(axis=1) hour = df_origin[&#39;Date&#39;].dt.hour[0] if df_origin[&#39;Date&#39;].dt.freq != &#39;H&#39;: print(f" >>> [Warning]: VOCs组分数据时差存在不为1小时的时段! <<<") df_origin[&#39;Time&#39;] = [(hour + 16) * 3600 + 3600 * i for i in range(len(df_origin[&#39;Date&#39;]))] df_origin[&#39;Time&#39;] = df_origin[&#39;Time&#39;].astype(int) # sta_loc = station_info(df_origin[&#39;城市&#39;].unique()[0]) sta_loc = [-1 * df_origin[&#39;经度&#39;].unique()[0], df_origin[&#39;纬度&#39;].unique()[0]] os.system("echo set LAT = " + str(sta_loc[1]) + ">> " + os.environ.get(&#39;ENVFILE&#39;)) os.system("echo set LON = " + str(sta_loc[0]) + ">> " + os.environ.get(&#39;ENVFILE&#39;)) os.system("echo set STEP_NUM = &#39;" + str(int((df_origin[&#39;Time&#39;].values[-1] - df_origin[&#39;Time&#39;].values[0]) / 3600)) + "&#39;>> " + os.environ.get(&#39;ENVFILE&#39;)) lim_ymd = df_origin[&#39;Time&#39;].apply(lambda x: x == 16*3600) os.system("echo set bUYY = &#39;" + str((df_origin[&#39;Date&#39;][lim_ymd] + timedelta(days=-1)).dt.year.values[0]).zfill(4) + "&#39;>> " + os.environ.get(&#39;ENVFILE&#39;)) os.system("echo set bUMM = &#39;" + str((df_origin[&#39;Date&#39;][lim_ymd] + timedelta(days=-1)).dt.month.values[0]).zfill(2) + "&#39;>> " + os.environ.get(&#39;ENVFILE&#39;)) os.system("echo set bUDD = &#39;" + str((df_origin[&#39;Date&#39;][lim_ymd] + timedelta(days=-1)).dt.day.values[0]).zfill(2) + "&#39;>> " + os.environ.get(&#39;ENVFILE&#39;)) print("[Notice] >>> 开始数据换算及单位调整 <<<") df_origin = base_trans(df_origin, map_dict) print("[Notice] >>> 完成数据换算及单位调整 <<<") print("[Notice] >>> 开始生成敏感性分析情景数据 <<<") rir_generator(df_origin.copy(), df_map) print("[Notice] >>> 完成生成敏感性分析情景数据 <<<") print("[Notice] >>> 开始生成EKMA情景数据 <<<") ekma_generator(df_origin.copy(), df_map.to_dict(orient=&#39;list&#39;)) print("[Notice] >>> 完成生成EKMA情景数据 <<<") print("[Notice] >>> 开始处理基准情景数据及模型配置 <<<") df_all = df_origin.copy() species = [] env_var = [&#39;H2O&#39;, &#39;DEC&#39;, &#39;BLHEIGHT&#39;, &#39;DILUTE&#39;, &#39;JFAC&#39;, &#39;ROOF&#39;, &#39;ASA&#39;] env_opt = [&#39;CALC&#39;, &#39;CALC&#39;, &#39;NOTUSED&#39;, &#39;NOTUSED&#39;, 1.0, &#39;OPEN&#39;, &#39;NOTUSED&#39;] pho_env = [] spe_path = os.path.join(os.environ.get("BASECST"), &#39;species&#39;) env_path = os.path.join(os.environ.get("BASECST"), &#39;environment&#39;) pho_path = os.path.join(os.environ.get("BASECST"), &#39;photolysis&#39;) reac_path = os.path.join(os.environ.get("BASEOUT"), &#39;reactionRates&#39;) os.makedirs(spe_path, exist_ok=True) os.makedirs(env_path, exist_ok=True) os.makedirs(pho_path, exist_ok=True) os.makedirs(reac_path, exist_ok=True) for key, value in map_dict.items(): if key in df_all.columns: if value not in [&#39;TEMP&#39;, &#39;PRESS&#39;, &#39;RH&#39;, &#39;J4&#39;, &#39;PAN&#39;, &#39;HCHO&#39;, &#39;CH4&#39;]: species.append(value) df_all[[&#39;Time&#39;, key]].to_csv(os.path.join(spe_path, value), header=None, index=False, sep=&#39; &#39;) elif value in [&#39;TEMP&#39;, &#39;PRESS&#39;, &#39;RH&#39;]: env_var.append(value) env_opt.append(&#39;CONSTRAINED&#39;) df_all[[&#39;Time&#39;, key]].to_csv(os.path.join(env_path, value), header=None, index=False, sep=&#39; &#39;) elif value == &#39;J4&#39;: pho_env.append(&#39;{&#39; + value + &#39;}&#39;) df_all[[&#39;Time&#39;, key]].to_csv(os.path.join(pho_path, value), header=None, index=False, sep=&#39; &#39;) else: species.append(&#39;{&#39; + value + &#39;}&#39;) df_all[[&#39;Time&#39;, key]].to_csv(os.path.join(spe_path, value), header=None, index=False, sep=&#39; &#39;) else: if value == &#39;TEMP&#39;: env_var.append(value) env_opt.append(298.15) elif value == &#39;RH&#39;: env_var.append(value) env_opt.append(70) elif value == &#39;PRESS&#39;: env_var.append(value) env_opt.append(1013.25) else: continue env_ind = [i + 1 for i in range(len(env_var))] env_dict = {&#39;ind&#39;: env_ind, &#39;var&#39;: env_var, &#39;opt&#39;: env_opt} df_env = pd.DataFrame(env_dict) df_env.to_csv(os.path.join(os.environ.get("MODCFG"), &#39;environmentVariables.config&#39;), header=None, index=False, sep=&#39; &#39;) s_j = pd.DataFrame(pho_env) s_j.to_csv(os.path.join(os.environ.get("MODCFG"), &#39;photolysisConstrained.config&#39;), header=None, index=False, sep=&#39; &#39;) s_species = pd.Series(species) s_species.to_csv(os.path.join(os.environ.get("MODCFG"), &#39;speciesConstrained.config&#39;), header=None, index=False, sep=&#39; &#39;) print("[Notice] >>> 完成处理基准情景数据及模型配置 <<<") if __name__ == &#39;__main__&#39;: all_data_file = sys.argv[1] all_map_file = sys.argv[2] main_process(all_data_file, all_map_file)
09-26
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值