我从命令行参数接收命名空间对象。 而且我不想修改它。 我可以这样做,还是你有一些想法?
# -*- coding: utf-8 -*-
import argparse
def parse_args():
parser = argparse.ArgumentParser(description='This script is ...')
parser.add_argument('--confdir', type=str, required=True)
parser.add_argument('--outdir', type=str, required=True)
return parser.parse_args()
if __name__ == '__main__':
mutable_namespace = parse_args()
# I want to prevent overwrite like that.
mutable_namespace.confdir = "xxx"
答案 0 :(得分:2)
我最初提出了自定义Namespace类,但我喜欢将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)
现在定义一个namedtuple
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
课程。
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)
现在args
和anamespace
引用相同的MyNamespace
对象。只要getattr(anamespace, adest)
和setattr(anamespace, adest, avalue)
有效,argparse
就可以使用此命名空间对象。
现在,您可以允许setattr(anamespace, 'string', 'value')
,但不允许anamespace.string = value
吗?我认为你可以,但需要很好地理解后一种表达方式的工作原理。它可能只需要定制.__setattr__
,但我暂时没有研究过Python的这个方面。
通过设计,使用像这样的自定义类,可以使用argparse
命名空间'猴子补丁',甚至可以接受。
答案 1 :(得分:1)
您可以在mutable_namespace中重新定义__setattr__
:
class NotMutableException(Exception):pass
class SomeObject(object):
def init(self):
self.x = 10
self.y = 20
some_obj = SomeObject()
some_obj.z = 30
def not_setattr(self, name, value):
raise NotMutableException
type(some_obj).__setattr__ = not_setattr
some_obj.a = 1000