如何创建 Python 命名空间(argparse.parse_args 值)?

Posted

技术标签:

【中文标题】如何创建 Python 命名空间(argparse.parse_args 值)?【英文标题】:How do I create a Python namespace (argparse.parse_args value)? 【发布时间】:2015-04-05 09:58:06 【问题描述】:

为了以交互方式测试我的 python 脚本,我想创建一个 Namespace 对象,类似于 argparse.parse_args() 返回的对象。 显而易见的方式,

>>> import argparse
>>> parser = argparse.ArgumentParser()
>>> parser.parse_args()
Namespace()
>>> parser.parse_args("-a")
usage: [-h]
: error: unrecognized arguments: - a

Process Python exited abnormally with code 2

可能会导致 Python repl 退出(如上)一个愚蠢的错误。

那么,创建具有给定属性集的 Python 命名空间的最简单方法是什么?

例如,我可以即时创建dict (dict([("a",1),("b","c")])),但不能将其用作Namespace

AttributeError: 'dict' object has no attribute 'a'

【问题讨论】:

【参考方案1】:

你可以创建一个简单的类:

class Namespace:
    def __init__(self, **kwargs):
        self.__dict__.update(kwargs)

在属性方面,它的工作方式与 argparse Namespace 类完全相同:

>>> args = Namespace(a=1, b='c')
>>> args.a
1
>>> args.b
'c'

或者,只需导入类;它可以从argparse 模块获得:

from argparse import Namespace

args = Namespace(a=1, b='c')

从 Python 3.3 开始,还有 types.SimpleNamespace,它基本上做同样的事情:

>>> from types import SimpleNamespace
>>> args = SimpleNamespace(a=1, b='c')
>>> args.a
1
>>> args.b
'c'

这两种类型是不同的; SimpleNamespace主要用于sys.implementation属性和time.get_clock_info()的返回值。

进一步比较:

两个类都支持相等测试;对于同一类的两个实例,如果它们具有相同的属性和相同的值,instance_a == instance_b 为真。 这两个类都有一个有用的__repr__ 来显示它们具有哪些属性。 Namespace() 对象支持收容测试;如果命名空间实例具有属性 namend attrname'attrname' in instance 为真。 SimpleNamespace 没有。 Namespace() 对象有一个未记录的 ._get_kwargs() 方法,该方法返回该实例的 (name, value) 属性的排序列表。您可以使用 sorted(vars(instance).items()) 为任一类获得相同的结果。 虽然SimpleNamespace() 是用C 实现的,Namespace() 是用Python 实现的,但属性访问并不快,因为它们都使用相同的__dict__ 存储属性。对于 SimpleNamespace() 实例,相等性测试和生成表示的速度要快一些。

【讨论】:

之前的简单类其实就是types.SimpleNamespace:见docs.python.org/dev/library/types.html#types.SimpleNamespace。 @Ofer: 不,SimpleNamespace 实际上并没有被argparse 使用; argparse.Namespace 是该库独有的纯 Python 类,types.SimpleNamespace 是最初为 sys.implementation 开发的类,后来也用于 time.get_clock_info()。它是用 C 语言实现的。 要像argparse.Namespace那样实现'attrname' in instance,可以在上面的类定义中添加__contains__方法:def __contains__(self, item): return item in self.__dict__【参考方案2】:

argparse documentation 显示您正在尝试做的各种示例:

import argparse
parser = argparse.ArgumentParser()
parser.add_argument("-a")
parser.parse_args(['-a 12'])
>>> Namespace(a=' 12')

【讨论】:

不好,正如我在问题中解释的那样:一个小错误,repl dead 这不允许您以交互方式测试使用 Namespace 实例的代码。 @sds 我可能遗漏了您问题的“repl is dead”部分的内容,但这不是因为您使用的ArgumentParser 缺少add_argument 调用吗?我知道您不想在测试中重新创建相同的ArgumentParser,但可以在要检索的测试中调用的单独方法中创建它。 @MartijnPieters 你不能以这种方式创建ArgumentParser,然后将它传递给你使用它的方法吗? `my_method_using_arg_parse(fake_namespace)【参考方案3】:

现在建议使用类型模块中的 SimpleNamespace。它与接受的答案做同样的事情,除了它会更快并且有更多的内置函数,例如 equals 和 repr。

from types import SimpleNamespace

sn = SimpleNamespace()
sn.a = 'test'
sn.a

# output
'test'

【讨论】:

argparse.Namespace 也实现了__repr____eq__SimpleNamespace is 在 C 中实现,但只有相等测试和 repr() 输出会因此更快一些。属性访问同样快,因为两者都使用完全相同的机制来存储和查找属性。 argparse.Namespace() 也实现了__contains__,所以可以使用if something in ns_instance,还有一个未记录的._get_kwargs() 方法; SimpleNamespace() 也没有。

以上是关于如何创建 Python 命名空间(argparse.parse_args 值)?的主要内容,如果未能解决你的问题,请参考以下文章

Python Argparse:获取用于命名空间变量的命令行参数

使用其他命名空间/字典更新 argparse 命名空间

带有嵌套命名空间的 argparse 子命令

Python argparse:可以命名或定位的命令行参数

在 Python 中轻松地将变量从/向命名空间/字典转储

复用代码Python接收命令行参数:argparse模块