入门开发者将所有的参数都写在代码里面;
初级开发者将部分参数写在代码里
中级开发者将命令参数写在代码里
高级开发者将所有参数写在命令参数和配置文件里可以发现,这些做法的改变确实越来越复杂,但是代码的可扩展性也越好越好了
argparse 是什么?
argparse 是 Python 内置的一个用于命令项选项与参数解析的模块,通过在程序中定义好我们需要的参数,然后在程序启动命令行传递我们想要改变的参数
使用argparse的最小使用例子
步骤:
(1)import argparse 首先导入模块
(2)parser = argparse.ArgumentParser() 创建一个解析对象
(3)parser.add_argument() 向该对象中添加你要关注的命令行参数和选项。第三步中,可以添加多个我们想要的参数。如下面的例子
(4)parser.parse_args() 进行解析
(5)vars()将解析值转换成字典对象,然后就可以使用了
例子如下,文件名为main.py
# 文件名为main.py
class DoSomething():
def working(self):
pass
if __name__ == '__main__':
import argparse # 步骤一:导入模块
# 启动参数
parser = argparse.ArgumentParser() # 步骤二:创建一个解析对象
# 步骤三:向解析对象中添加你要关注的命令行参数和选项
parser.add_argument('--labels_dir', type=str,
help='标签目录', default='./data/labels') # help的值就是你对这个参数labels_dir的作用描述
parser.add_argument('--models_dir', type=str,
help='模型跟目录', default='./data/models') # type的值就是你对这个参数models_dir数据类型的指定
parser.add_argument('--last_dir_name', type=str,
help='文件后序名', default='_seq_month_serial') # default的值就是你对这个参数last_dir_name设置的默认值
parser.add_argument('--batch_size', type=int,
help='批次大小', default=64)
parser.add_argument('--classes', type=int,
help='聚类数', default=9)
parser.add_argument('--predict_date', type=str,
help='预测年月', default='202101')
parser.add_argument('--last_date', type=str,
help='输入最后年月', default='202001')
parser.add_argument('--only_predict', action="store_true", # action的值就是你对这个参数only_predict设置了布尔数据类型,并且默认值为True
help='只识别,不训练')
parser.add_argument('--delete_model', action="store_true",
help='先删除模型,仅在训练时使用')
parser.add_argument('--hidden_size', type=int,
help='模型维度', default=128)
parser.add_argument('--learning_rate', type=float,
help='学习速率', default=5e-4)
parser.add_argument('--export_excel', action="store_true",
help='导出excel')
parser.add_argument('--loss_type', type=str,
help='loss类型', default='categorical_crossentropy')
parser.add_argument('--avg_model_num', type=int,
help='平均模型数', default=10)
parser.add_argument('--get_data', action="store_true",
help='重新获取数据')
argparse_args = parser.parse_args() # 步骤四:进行解析
# vars() 函数返回对象object的属性和属性值的字典对象。
args_default = vars(argparse_args) # 步骤五,将解析值转换成字典对象,然后就可以使用了
print(type(argparse_args))
print(argparse_args)
print('分割线')
print(type(args_default)) # 是字典数据类型
print(args_default) # 将这个字典传入到程序中,就可以拿到这些参数的所有值了
运行,得出下面的结果
<class 'argparse.Namespace'>
Namespace(labels_dir='./data/labels', models_dir='./data/models', last_dir_name='_seq_month_serial', batch_size=64, classes=9, predict_date='202101', last_date='202001', only_predict=False, delete_model=False, hidden_size=128, learning_rate=0.0005, export_excel=False, loss_type='categorical_crossentropy', avg_model_num=10, get_data=False)
分割线
<class 'dict'>
{'labels_dir': './data/labels', 'models_dir': './data/models', 'last_dir_name': '_seq_month_serial', 'batch_size': 64, 'classes': 9, 'predict_date': '202101', 'last_date': '202001', 'only_predict': False, 'delete_model': False, 'hidden_size': 128, 'learning_rate': 0.0005, 'export_excel': False, 'loss_type': 'categorical_crossentropy', 'avg_model_num': 10, 'get_data': False}
argparse实际工作的用法
问题背景
上面的对法如果你程序就只是一个文件,那就已经满足了。如果你项目比较大,有很多基础的命令配置参数在很多启动文件中都用到了,当然你可以在各自的启动文件中都写上,但是如果你这么做,后续参数值的修改和变动将非常麻烦,因为你需要同时修改很多启动文件,有没有办法修改一个启动文件就可以呢。办法是有的。
解决办法
通过新建一个类来实现,文件名为share_args.py。这个类里面写上你所需要的命令参数
class ShareArgs():
# args就是整个项目经常使用到的默认参数,经常不需要进行变动,所以就写在这里。然后通过update的更新写到启动文件的字典参数里面
args = {
"labels_dir":"./shop_group/month_w_amt/data/labels", # 标签目录
"labels_output_dir":"./shop_group/month_w_amt/data/labels_output", # 聚类导出标签目录
"common_datas_dir":"./data", # 共用数据目录
"only_predict": False, # 只识别,不训练
"delete_model": True, # 先删除模型,仅在训练时使用
"export_excel": False, # 导出excel
"classes": 12, # 聚类数
"batch_size": 16,
"hidden_size": 32,
"max_nrof_epochs": 100,
"learning_rate": 0.0005,
"loss_type": "categorical_crossentropy",
"avg_model_num": 10,
"steps_per_epoch": 4.0, # 4.0
"lr_callback_patience": 4,
"lr_callback_cooldown": 1,
"early_stopping_callback_patience": 6,
"get_data": True,
}
def get_args(): # 获取参数字典
return ShareArgs.args
def set_args(args): # 一次性更新修改所有参数字典的值
ShareArgs.args = args
def set_args_value(key, value): # 根据索引更新参数字典的值
ShareArgs.args[key] = value
def get_args_value(key, default_value=None): # 获取指定索引的默认参数的值
return ShareArgs.args.get(key, default_value)
def contain_key(key): # 判断索引是否在参数字典里面
return key in ShareArgs.args.keys()
def update(args): # 用于更新字典中的键/值对,可以修改存在的键对应的值,也可以添加新的键/值对到字典中
ShareArgs.args.update(args)
启动文件如下,文件名为main.py
import sys
base_dir = ''
sys.path.append(base_dir)
from share_args import ShareArgs
class DoSomething():
def working(self):
print('ShareArgs.args : ',ShareArgs.args)
if __name__ == '__main__':
import argparse # 步骤一:导入模块
# 启动参数
parser = argparse.ArgumentParser() # 步骤二:创建一个解析对象
# 步骤三:向解析对象中添加你要关注的命令行参数和选项
parser.add_argument('--labels_dir', type=str,
help='标签目录', default='./data/labels') # help的值就是你对这个参数labels_dir的作用描述
parser.add_argument('--models_dir', type=str,
help='模型跟目录', default='./data/models') # type的值就是你对这个参数models_dir数据类型的指定
parser.add_argument('--last_dir_name', type=str,
help='文件后序名', default='_seq_month_serial') # default的值就是你对这个参数last_dir_name设置的默认值
parser.add_argument('--batch_size', type=int,
help='批次大小', default=64)
parser.add_argument('--classes', type=int,
help='聚类数', default=9)
parser.add_argument('--predict_date', type=str,
help='预测年月', default='202101')
parser.add_argument('--last_date', type=str,
help='输入最后年月', default='202001')
parser.add_argument('--only_predict', action="store_true", # action的值就是你对这个参数only_predict设置了布尔数据类型,并且默认值为True
help='只识别,不训练')
parser.add_argument('--delete_model', action="store_true",
help='先删除模型,仅在训练时使用')
parser.add_argument('--hidden_size', type=int,
help='模型维度', default=128)
parser.add_argument('--learning_rate', type=float,
help='学习速率', default=5e-4)
parser.add_argument('--export_excel', action="store_true",
help='导出excel')
parser.add_argument('--loss_type', type=str,
help='loss类型', default='categorical_crossentropy')
parser.add_argument('--avg_model_num', type=int,
help='平均模型数', default=10)
parser.add_argument('--get_data', action="store_true",
help='重新获取数据')
argparse_args = parser.parse_args() # 步骤四:进行解析
# vars() 函数返回对象object的属性和属性值的字典对象。
args_default = vars(argparse_args) # 步骤五,将解析值转换成字典对象,然后就可以使用了
# print(type(argparse_args))
# print(argparse_args)
# print('分割线')
# print(type(args_default)) # 是字典数据类型
# print(args_default) # 将这个字典传入到程序中,就可以拿到这些参数的所有值了
ShareArgs.update(args_default) # 将很多的默认参数更新到这里来
DoSomething().working()
结果如下。可以发现,类中默认的参数全部拿到了
ShareArgs.args : {'labels_dir': './data/labels', 'labels_output_dir': './yongjian/shop_group/month_w_amt/data/labels_output', 'common_datas_dir': './yongjian/data', 'only_predict': False, 'delete_model': False, 'export_excel': False, 'classes': 9, 'batch_size': 64, 'hidden_size': 128, 'max_nrof_epochs': 100, 'learning_rate': 0.0005, 'loss_type': 'categorical_crossentropy', 'avg_model_num': 10, 'steps_per_epoch': 4.0, 'lr_callback_patience': 4, 'lr_callback_cooldown': 1, 'early_stopping_callback_patience': 6, 'get_data': False, 'models_dir': './data/models', 'last_dir_name': '_seq_month_serial', 'predict_date': '202101', 'last_date': '202001'}
对argparse做不到的事情的补充
问题背景
在第二部分中已经解释了如何配合多个启动文件的问题,用一个类来解决。但是呢,还有个问题就是如果有很多配置参数变动比较频繁,例如连接数据库的账号、密码、端口、ip等等,这些数据变动多,而且数据需要一定的保密性,所以不能通过建一个类来进行传递,那该怎么办呢?
解决办法
通过读取配置文件config.yml来进行解决。可以把正式环境的配置信息放到config.yml里面,测试环境的配置信息放到configtest.py。这样可以确保整个项目读取到的共用信息的一致的,修改起来也很方便
教学说明
下面的流程先解释细节,然后再展现总体,请耐心看到最后
流程如下
config.yml的样式如下,表示正式环境的信息。
common:
server_ip: 10.23.167.20:9988
mip_server_ip: test-mip.ur.com.cn:8768
common_datas_dir: ./data
month_category_scale:
# export_db_database: test_ims # 测试
export_db_database: mimp # 正式
# export_db_host: 192.168.130.13 # 测试
export_db_host: 10.20.167.145 # 正式
# export_db_password: 123456 # 测试
export_db_password: 654321 # 正式
export_db_port: 4000
export_db_user: root
export_dir: ./month_category_scale/data/export
labels_dir: ./month_category_scale/data/labels
log_dir: ./month_category_scale/logs
log_level: DEBUG
models_dir: ./month_category_scale/data/models
ur_bi_dw_auth_mechanism: LDAP
ur_bi_dw_database: ur_ai_dw
ur_bi_dw_host: 10.23.167.20
ur_bi_dw_password: 123456789
ur_bi_dw_port: 21562
ur_bi_dw_save_dir: ./month_category_scale/data/ur_bi_dw_data
ur_bi_dw_user: urbiyetes
然后再建立一个文件,用于读取配置文件,文件名为:config_helper.py
# !pip install PyYaml # yaml文件的解析去B站看个10分钟教学视频即可学会,在这里不详细解释了
import yaml
def read_yml(file_path):
with open(file_path, 'r', encoding='utf-8') as file:
return yaml.load(file, Loader=yaml.FullLoader)
def get_config(base_dir, logger=None): # logger 表示日志对象
if not os.path.exists(os.path.join(base_dir, './data/is_local.txt')):
if logger:
logger.info('加载正式环境配置:./config.yml')
else:
print('加载正式环境配置:./config.yml')
config = read_yml(os.path.join(base_dir, './config.yml'))
else:
if logger:
logger.info('加载测试环境配置:./config_dev.yml')
else:
print('加载测试环境配置:./config_dev.yml')
config = read_yml(os.path.join(base_dir, './config_dev.yml'))
return config
改变之后的main.py文件如下
import sys
base_dir = ''
sys.path.append(base_dir)
from share_args import ShareArgs
class DoSomething():
def working(self, config=None):
print('ShareArgs.args : ',ShareArgs.args)
print('config', config)
if __name__ == '__main__':
import argparse # 步骤一:导入模块
# 启动参数
parser = argparse.ArgumentParser() # 步骤二:创建一个解析对象
# 步骤三:向解析对象中添加你要关注的命令行参数和选项
parser.add_argument('--labels_dir', type=str,
help='标签目录', default='./data/labels') # help的值就是你对这个参数labels_dir的作用描述
parser.add_argument('--models_dir', type=str,
help='模型跟目录', default='./data/models') # type的值就是你对这个参数models_dir数据类型的指定
parser.add_argument('--last_dir_name', type=str,
help='文件后序名', default='_seq_month_serial') # default的值就是你对这个参数last_dir_name设置的默认值
parser.add_argument('--batch_size', type=int,
help='批次大小', default=64)
parser.add_argument('--classes', type=int,
help='聚类数', default=9)
parser.add_argument('--predict_date', type=str,
help='预测年月', default='202101')
parser.add_argument('--last_date', type=str,
help='输入最后年月', default='202001')
parser.add_argument('--only_predict', action="store_true", # action的值就是你对这个参数only_predict设置了布尔数据类型,并且默认值为True
help='只识别,不训练')
parser.add_argument('--delete_model', action="store_true",
help='先删除模型,仅在训练时使用')
parser.add_argument('--hidden_size', type=int,
help='模型维度', default=128)
parser.add_argument('--learning_rate', type=float,
help='学习速率', default=5e-4)
parser.add_argument('--export_excel', action="store_true",
help='导出excel')
parser.add_argument('--loss_type', type=str,
help='loss类型', default='categorical_crossentropy')
parser.add_argument('--avg_model_num', type=int,
help='平均模型数', default=10)
parser.add_argument('--get_data', action="store_true",
help='重新获取数据')
argparse_args = parser.parse_args() # 步骤四:进行解析
# vars() 函数返回对象object的属性和属性值的字典对象。
args_default = vars(argparse_args) # 步骤五,将解析值转换成字典对象,然后就可以使用了
# print(type(argparse_args))
# print(argparse_args)
# print('分割线')
# print(type(args_default)) # 是字典数据类型
# print(args_default) # 将这个字典传入到程序中,就可以拿到这些参数的所有值了
ShareArgs.update(args_default) # 将很多的默认参数更新到这里来
# DoSomething().working()
import config_helper as config_helper
config = config_helper.get_config(base_dir, None)
DoSomething().working(config)
结果如下
加载正式环境配置:./config.yml
ShareArgs.args : {'labels_dir': './data/labels', 'labels_output_dir': './shop_group/month_w_amt/data/labels_output', 'common_datas_dir': './data', 'only_predict': False, 'delete_model': False, 'export_excel':
False, 'classes': 9, 'batch_size': 64, 'hidden_size': 128, 'max_nrof_epochs': 100, 'learning_rate': 0.0005, 'loss_type': 'categorical_crossentropy', 'avg_model_num': 10, 'steps_per_epoch': 4.0, 'lr_callback_patience': 4, 'lr_callback_cooldown': 1, 'early_stopping_callback_patience': 6, 'get_data': False, 'models_dir': './data/models', 'last_dir_name': '_seq_month_serial', 'predict_date': '202101', 'last_date': '202001'}
config : {'common': {'server_ip': '10.23.167.20:9988', 'mip_server_ip': 'test-mip.ur.com.cn:8768', 'common_datas_dir': './data'}, 'month_category_scale': {'export_db_database': 'mimp', 'export_db_host': '10.20.167.145', 'export_db_password': 654321, 'export_db_port': 4000, 'export_db_user': 'root', 'export_dir': './month_category_scale/data/export', 'labels_dir': './month_category_scale/data/labels', 'log_dir': './month_category_scale/logs', 'log_level': 'DEBUG', 'models_dir': './month_category_scale/data/models', 'ur_bi_dw_auth_mechanism': 'LDAP', 'ur_bi_dw_database': 'ur_ai_dw', 'ur_bi_dw_host': '10.23.167.20', 'ur_bi_dw_password': 123456789, 'ur_bi_dw_port': 21562, 'ur_bi_dw_save_dir': './month_category_scale/data/ur_bi_dw_data', 'ur_bi_dw_user': 'urbiyetes'}}
总结
- 掌握argparse的基础用法
- 掌握argparse在工作中的用法
- 配合config.yml配置文件,满足项目配置文件的用法