Python:从 arg 解析器到字典

Posted

技术标签:

【中文标题】Python:从 arg 解析器到字典【英文标题】:Python: From arg parser to dictionary 【发布时间】:2021-08-26 16:06:03 【问题描述】:

我在 Python 3.8 中有一个名为“stores.py”的文件。该文件有一个名为“scan_transactions”的方法,它采用 2 个位置参数:“store”和“checkpoint”。该方法基本上通过使用 REGEX 模式来扫描 PostgreSQL 表中的存储事务。当代码到达事务表中该特定存储的最后一个事务 id 时,然后使用另一个表(检查点表)并进行更新以指示任何给定存储的最新最大事务 id。

目前,我正在从一个类似于下面的预定义字典中传递两个参数:

dict_stores = 'store1': 'checkpoint_store1', 'store2': 'checkpoint_store2','store3': 'checkpoint_store3'

目前代码如下所示:

def store_transactions(store: str, checkpoint_name: str)
.
.
.
.
.

if __name__ == '__main__':

    for store, checkpoint in shops.dict_stores.items():
        LOG.debug(f'Processing store : store, checkpoint: checkpoint')
        store_transactions(store, checkpoint)

我现在希望使其更具动态性,并允许用户在执行之前将他们想要处理交易的商店作为批处理作业传递。这将使用下面的命令行:

"stores.py" --stores -store1 -store2 -store3...etc.

然后上面的命令将替换这个预先固定的字典并动态创建一个字典。有谁知道我如何使用“arg parser”以某种方式以编程方式将参数“-shop 1”、“-shop2”转换为像上面那样的字典(将它们各自的检查点作为值)并使用相同的循环处理所有商店我目前正在运行?

【问题讨论】:

这看起来更像是一个列表;这是默认行为 嗨@crissal,你能详细说明一下吗? argparse 文档解释说args=parser.parse_args() 解析sys.argv 列表(来自shell/解释器),并返回一个Namespace 对象。 vars(args) 将该对象转换为 dict。您可以轻松地从中获取值。此外,您可以传递类似的字符串列表,而不是 sys.argv Adding Arguments 中的第一个示例似乎是您想要的。它的形式是supermarkets.py --stores store1 store2 ...。它减去单个破折号,但您不想要传统上标记单个字符标志的单个破折号。 所以,基本上,您想通过argparse 传递链接参数对的列表?您不妨删除所有关于 postgres 和超市的讨论,这会分散注意力。不过,将 store1、checkpoint_store1 等作为示例对保留没有错。 【参考方案1】:

注意,我认为你需要使用 positional argparse 参数让它们重复(即你没有 --store 选项名称)。或者我可能对 optparse 感到困惑,这些天主要使用 Click。

文档的nargs 部分涵盖了这一点,因此看起来您也可以使用--store。例子不是很清楚。也就是说,这对用户来说需要更多的打字,所以我会选择位置。

import argparse

#the existing dictionary
lookup = 'store1': 'checkpoint_store1', 'store2': 'checkpoint_store2','store3': 'checkpoint_store3'

#from doc @ https://docs.python.org/3/library/argparse.html#example
parser = argparse.ArgumentParser(description='Process some stores.')

#Option 1 your loop checks for valid stores
# parser.add_argument('stores', type=str, nargs='+', help='stores')

#Option2 argparse checks for valid stores
parser.add_argument('stores', type=str, nargs='+', help='stores', choices=lookup.keys())

args = parser.parse_args()
user_stores = args.stores
dict_stores = 

#check in loop
for store in user_stores:
    try:
        dict_stores[store] = lookup[store]
    #pragma: no cover pylint: disable=unused-variable
    except (KeyError,) as e: 
        print(f" unknown store store. known : ' '.join(lookup.keys())")

# if you use argparse to check this can be simplified to
# dict_stores[store] = store: lookup[store] for store in user_stores


print(f"dict_stores")

输出:

(venv38) me@explore$ py test_301_arg.py store1 store2
'store1': 'checkpoint_store1', 'store2': 'checkpoint_store2'


(venv38) me@explore$ py test_301_arg.py store1 store4
usage: test_301_arg.py [-h] store1,store2,store3 [store1,store2,store3 ...]
test_301_arg.py: error: argument stores: invalid choice: 'store4' (choose from 'store1', 'store2', 'store3')


(venv38) me@explore$ py test_301_arg.py --help
usage: test_301_arg.py [-h] store1,store2,store3 [store1,store2,store3 ...]

Process some stores.

positional arguments:
  store1,store2,store3
                        stores

optional arguments:
  -h, --help            show this help message and exit

【讨论】:

这正是我所需要的——谢谢。我可以让现有字典来自我在 PostgreSQL 数据库中的检查点表吗?这将使它更加动态..该表具有以下列:checkpoint_id 和 checkpoint_name(checkpoint_store1、checkpoint_store2 等) 可能。如果 postgres 中存在 store1/checkpoint_store1 关联,我认为您没有理由不能动态填充 lookup。事实上,这将是一种比硬编码更强大的方法。 是的,不幸的是,这张表只有检查点名称列,没有商店。我只会在 checkpoint_name 列下找到 checkpoint_store2、checkpoint_store3 等。只有你认为的检查点名称,我仍然可以这样做吗? 这更像是一个数据库数据问题。在不知道您的数据库架构的情况下很难说。也许您需要加入另一张桌子。某处可能有一个store_id 列。恐怕这不是 *** 能够提供帮助的问题,也许问你的数据库人员?首先在纯 sql 中查询数据,直到结果中都有两列,然后您可以看到有关使用它加载 Python dict 的信息。 最后一件事使用 REGEX 模式扫描 PostgreSQL 表中的存储事务 让我的 SQL 编码器有点畏缩。如果表有很多行,请注意您有适当的索引以使其执行得相当好。请记住:生产数据库可能比测试数据库拥有更多。【参考方案2】:

我发现使用在, 上拆分的结构来读取可能性列表很方便

def parse_args(args_external=None):
    """ build an arguments object with required attributes from user input """

    parser = argparse.ArgumentParser(
        description="Example Program",
    )

    parser.add_argument(
        "--foo",
        default="",
        help="comma-separated collection of bars")

    arguments = parser.parse_args(args_external)  # enables automated testing (otherwise None -> sys.argv)

    _foo = []
    for bar in arguments.foo.split(","):
        if not bar:  # allow skipping ,,
            continue
        validatebar(bar)  # sys.exit with message if invalid
    arguments.foo = _foo  # clobber the original reference

这样消费

python3 ./myscript.py --foo bar1,bar2,bar3

【讨论】:

【参考方案3】:

替代解决方案:只需读取 JSON 配置文件,可能将参数设为文件名或 stdin 的触发器

import json

    ...
    with open(path_config) as fh:
        config = json.load(fh)  # config is now a Python dict

【讨论】:

以上是关于Python:从 arg 解析器到字典的主要内容,如果未能解决你的问题,请参考以下文章

python字典构造函数dict(mapping)解析

Arg 解析器错误:args = vars(ap.parse_args()) 发生异常:python

Python内置容器——字典,迭代器,列表解析

从 JSON 字符串到字典的简单解析器

python-django rest framework框架之解析器

Python 迭代器生成器和列表解析