Is it possible to convert a namespace object from mutable to immutable?

I am getting a namespace object from command line arguments. And I don't want to change it. Can I do this or do you have any 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"

      

0


source to share


2 answers


I suggested my own namespace class at first, but I like this idea of ​​copying args

to NamedTuple better.

Namedtuple

Another option is to copy the values ​​from args

into an immutable object / class. A named tuple can do the job nicely.

Create namespace

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)

      

now define namedtuple

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

      

You can also get the names of the tuples from the namespace itself (after parsing)

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

      

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

      

and it is immutable:



In [1168]: foo.x=34
... 
AttributeError: can't set attribute

      

Such a named element cannot be used as a namespace because it setattr(foo,'x',34)

generates the same error.

The clean way to do it all is to wrap the whole thing in a function:

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

      

The calling code never sees mutable args

, just immutable foo

.

Custom namespace class

To build the answer Ingaz

, argparse

you can use your own class 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)

      

Now args

and anamespace

refer to the same object MyNamespace

. So far, getattr(anamespace, adest)

and setattr(anamespace, adest, avalue)

work, argparse

you can use the namespace object.

Now you can allow setattr(anamespace, 'string', 'value')

but deny anamespace.string = value

? I think you can, but it will require a good understanding of how the last expression works. It might just require customization .__setattr__

, but I haven't learned this aspect of Python in a while.

By design, this is possible and even acceptable for "monkey patches" in the namespace argparse

- with a custom class like this.

+2


source


You can override __setattr__

mutable_namespace in your space:



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

      

+1


source







All Articles