Python 我可以将名称空间对象从可变转换为不可变吗?

Python 我可以将名称空间对象从可变转换为不可变吗?,python,python-3.x,argparse,Python,Python 3.x,Argparse,我从命令行参数接收名称空间对象。 我不想修改它。 我可以这样做吗?或者你有什么想法 # -*- 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_

我从命令行参数接收名称空间对象。 我不想修改它。 我可以这样做吗?或者你有什么想法

# -*- 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"

您可以在可变名称空间中重新定义
\uuuuu setattr\uuuu

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

您可以在可变名称空间中重新定义
\uuuuu setattr\uuuu

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

我最初提出了自定义名称空间类,但我喜欢将
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)
您还可以从名称空间本身获取元组名称(解析后)

使用
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
这样的namedtuple不能用作名称空间,因为
setattr(foo,'x',34)
会产生相同的错误

完成这一切的一种干净方法是将其全部封装在一个函数中:

def do_parse():
   parser = ....
   Foo = namedtuple(...)
   args = parser.parse_args()
   foo = Foo(**vars(args))
   return foo
调用代码从不看到可变的
args
,只看到不可变的
foo

自定义命名空间类 要基于
Ingaz
answer,
argparse
可以使用您自己的
命名空间

类MyNamespace(argparse.Namespace):
通过
anamespace=MyNamespace()
args=parser.parse_args(名称空间=anamespace)
现在
args
anamespace
引用相同的
MyNamespace
对象。只要
getattr(anamespace,adest)
setattr(anamespace,adest,avalue)
起作用,
argparse
就可以使用这个名称空间对象

现在,您可以允许
setattr(anamespace,'string','value')
,但不允许
anamespace.string=value
?我想你可以,但这需要你很好地理解后一种表达方式是如何工作的。它可能只需要定制
。\uuuu setattr\uuuu
,但我已经有一段时间没有研究Python的这一方面了


通过设计,将
argparse
名称空间与这样一个自定义类“猴子补丁”是可能的,甚至是可以接受的。

我最初提出了自定义名称空间类,但我更喜欢将
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)
您还可以从名称空间本身获取元组名称(解析后)

使用
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
这样的namedtuple不能用作名称空间,因为
setattr(foo,'x',34)
会产生相同的错误

完成这一切的一种干净方法是将其全部封装在一个函数中:

def do_parse():
   parser = ....
   Foo = namedtuple(...)
   args = parser.parse_args()
   foo = Foo(**vars(args))
   return foo
调用代码从不看到可变的
args
,只看到不可变的
foo

自定义命名空间类 要基于
Ingaz
answer,
argparse
可以使用您自己的
命名空间

类MyNamespace(argparse.Namespace):
通过
anamespace=MyNamespace()
args=parser.parse_args(名称空间=anamespace)
现在
args
anamespace
引用相同的
MyNamespace
对象。只要
getattr(anamespace,adest)
setattr(anamespace,adest,avalue)
起作用,
argparse
就可以使用这个名称空间对象

现在,您可以允许
setattr(anamespace,'string','value')
,但不允许
anamespace.string=value
?我想你可以,但这需要你很好地理解后一种表达方式是如何工作的。它可能只需要定制
。\uuuu setattr\uuuu
,但我已经有一段时间没有研究Python的这一方面了


通过设计,它是可能的,甚至可以接受“monkey patch”的
argparse
名称空间-使用这样的自定义类。

在Python中锁定变量?只要。。。不要修改它?Python中没有什么比const更像
const
。通常的哲学是,如果你不想做某件事,你就不去做。这就是为什么我们也没有私人的。谢谢你的告别。我明白了,我的想法在Python中是不合适的。我很明白。我要改道。非常感谢。相关:在Python中锁定变量?只是。。。不要修改它?Python中没有什么比const更像
const
。通常的哲学是,如果你不想做某件事,你就不去做。这就是为什么我们也没有私人的。谢谢你的告别。我明白了,我的想法在Python中是不合适的。我很明白。我要改道。非常感谢。相关:如果您对
argparse
命名空间
执行此操作,那么您就破坏了
argparse
,以获取将来可能使用它的代码中的任何其他内容。我想我会提醒你的。Monkeypatching核心类来禁用它们是一个很大的禁忌。@ShadowRanger:OP的想法从一开始就很奇怪。所以它也有同样奇怪的答案。这不是一个奇怪的想法。您可以定义自己的
命名空间
类。只要允许解析器使用
getattr
setattr
获取和设置属性,它就应该可以工作。如果您对
argparse
命名空间
执行此操作,您只需断开
argparse
中将来可能使用它的任何其他代码。我想我会提醒你的。Monkeypatching核心类来禁用它们是一个很大的禁忌。@ShadowRanger:OP的想法从一开始就很奇怪。所以它也有同样奇怪的答案。这不是一个奇怪的想法。您可以定义自己的
命名空间
类。只要允许解析器使用
getattr
setattr
获取和设置属性,它就应该可以工作