我最初提出了自定义命名空间类,但我喜欢这种复制的想法args
到 NamedTuple 更好。
命名元组
另一种选择是复制值args
到一个不可变的对象/类。命名元组可能会很好地完成这项工作。
创建命名空间
In [1157]: dest=['x','y']
In [1158]: args=argparse.Namespace()
In [1159]: for name in dest:
......: setattr(args, name, 23)
......:
In [1160]: args
Out[1160]: Namespace(x=23, y=23)
现在定义一个命名元组
In [1161]: from collections import namedtuple
In [1163]: Foo = namedtuple('Foo',dest)
您还可以从命名空间本身获取元组名称(解析后)
Foo = namedtuple('Foo',vars(args).keys())
创建这样一个元组,其值来自args
:
In [1165]: foo=Foo(**vars(args))
In [1166]: foo
Out[1166]: Foo(x=23, y=23)
In [1167]: foo.x
Out[1167]: 23
并且它是不可变的:
In [1168]: foo.x=34
...
AttributeError: can't set attribute
这样的命名元组不能用作命名空间,因为setattr(foo,'x',34)
产生相同的错误。
完成所有这些的一个干净方法是将其全部包装在一个函数中:
def do_parse():
parser = ....
Foo = namedtuple(...)
args = parser.parse_args()
foo = Foo(**vars(args))
return foo
调用代码永远不会看到可变的args
,只是不可变的foo
.
自定义命名空间类
建立在Ingaz
回答,argparse
可以用你自己的Namespace
class.
https://docs.python.org/3/library/argparse.html#the-namespace-object https://docs.python.org/3/library/argparse.html#the-namespace-object
class MyNamespace(argparse.Namespace):
pass
<customize one or more methods>
anamespace = MyNamespace()
args = parser.parse_args(namespace=anamespace)
Now args
and anamespace
参考相同的MyNamespace
目的。只要getattr(anamespace, adest)
and setattr(anamespace, adest, avalue)
work, argparse
可以使用这个命名空间对象。
现在,你可以允许setattr(anamespace, 'string', 'value')
,但不允许anamespace.string = value
?我认为你可以,但这需要很好地理解后一种表达方式的工作原理。可能只需要定制.__setattr__
,不过我已经有一段时间没有研究Python这方面的内容了。
通过设计,“猴子补丁”是可能的,甚至是可以接受的argparse
命名空间 - 具有这样的自定义类。