我可以将名称空间对象从可变对象转换为不可变对象吗? [英] Can I convert a namespace object from mutable to immutable?

查看:54
本文介绍了我可以将名称空间对象从可变对象转换为不可变对象吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我从命令行参数接收一个名称空间对象. 而且我不想修改它. 我可以这样做还是您有一些想法?

I receive a namespace object from command line arguments. And I don't want to modify it. Can I do that or do you have some ideas?

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

推荐答案

我最初提出了自定义命名空间类,但我喜欢将args更好地复制到NamedTuple的想法.

I initially proposed the custom Namespace class, but I like this idea of copying args to a NamedTuple better.

另一个选择是将值从args复制到不可变的对象/类.一个命名的元组可能会做得很好.

Another option is to copy the values from args to an immutable object/class. A named tuple might do the job nicely.

创建名称空间

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

now define a namedtuple

In [1161]: from collections import namedtuple
In [1163]: Foo = namedtuple('Foo',dest)

您还可以从命名空间本身获取元组名称(解析后)

You could also get the tuple names from the Namespace itself (after parsing)

Foo = namedtuple('Foo',vars(args).keys())

使用args中的值创建这样的元组:

create such a tuple with values from 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)会产生相同的错误.

Such a namedtuple cannot be used as a Namespace, since setattr(foo,'x',34) produces the same error.

完成所有这些操作的一种干净方法是将其全部包装在一个函数中:

A clean way to do all of this is to wrap it all in a function:

def do_parse():
   parser = ....
   Foo = namedtuple(...)
   args = parser.parse_args()
   foo = Foo(**vars(args))
   return foo

调用代码从不会看到可变的args,而只有不变的foo.

The calling code never sees the mutable args, just the immutable foo.

要基于Ingaz答案,argparse可以使用您自己的Namespace类.

To build on Ingaz answer, argparse can use your own Namespace class.

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)

现在argsanamespace引用相同的MyNamespace对象.只要getattr(anamespace, adest)setattr(anamespace, adest, avalue)起作用,argparse都可以使用此命名空间对象.

Now args and anamespace reference the same MyNamespace object. As long as getattr(anamespace, adest) and setattr(anamespace, adest, avalue) work, argparse can use this namespace object.

现在,您可以允许setattr(anamespace, 'string', 'value'),但不允许anamespace.string = value吗?我认为可以,但是将需要对后一种表达的工作原理有一个很好的了解.它可能只需要自定义.__setattr__,但是我已经有一段时间没有研究Python的这一方面了.

Now, can you allow setattr(anamespace, 'string', 'value'), but disallow anamespace.string = value? I think you can, but it will require a good understanding of how the latter expression works. It may just require customizing .__setattr__, but I haven't studied this aspect of Python in a while.

通过设计,可以像这样的自定义类来猴子补丁" argparse名称空间,甚至是可以接受的.

By design it is possible, and even acceptable to 'monkey patch' the argparse namespace - with a custom class like this.

这篇关于我可以将名称空间对象从可变对象转换为不可变对象吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆