Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Easily dumping variables from/to namespaces/dictionaries in Python

Say I have several variables or objects in Python, a, b, c, ...

How can I easly dump these variables into a namespace in Python and restore them at a later time? (e.g. in the same way argparse wraps various variables into a namespace).

Here are two examples of how I would like to dump things to and from a namespace:

Dumping local variables into a namespace

function (bar):
   # We start with a, b and c
   a = 10
   b = 20
   c = "hello world"

   # We can dump anything we want into e, by just passing things as arguments:
   e = dump_into_namespace(a, b, c) 
   del a, b, c

   print (e.a + e.b) # Prints 30
   return e  # We can return e if we want. This is just a use case scenario

Dumping local variables from a namespace e

# We start with e, which for example was built with a call to 
# dump_into_namespace(a,b,c) somewhere else in the program,
# in which case e would hold a, b and c 

# We may receive e through a function call or load it from disk, e.g.:

function foo(e):

   # The following call creates the variables a,b and c
   # or updates their values if the already exist in memory
   dump_from_namespace(e) 
   del e

   print(a + b) # Prints 30
   print(c) # Prints hello world

My first question is: Is this possible at all in Python? (note that the method dump_into_namespace does not directly receive the names of the variables, at least as far as I can tell).

If the answer to the above is no, how could I do it with an interface like this?

e = dump_into_namespace('a', 'b', 'c')

Also, how would this be done this with a dictionary instead of a namespace?

There are a few threads that seem relevant addressing a dot-access of dynamically-defined variables, but I don't think they address the problem of dumping variables:

See also

  • Python: Extract variables out of namespace
  • Picklable data containers that are dumpable in the current namespace
  • Recursive DotDict
  • How to use a dot "." to access members of dictionary?
  • Javascript style dot notation for dictionary keys unpythonic?
  • Accessing dict keys like an attribute?
  • Recursively access dict via attributes as well as index access?
  • Python: Easily access deeply nested dict (get and set)
  • Are there any 'gotchas' with this Python pattern?

Are there any libraries that facilitate this type of access through dot notation?

Update:

It looks like there is a library that supports dot-accessible dictionaries in Python, called Bunch, but I am not sure it would support easily dumping as I defined it.

like image 975
Amelio Vazquez-Reina Avatar asked Feb 15 '13 21:02

Amelio Vazquez-Reina


People also ask

What is the best way to store dictionary Python?

Text Files The most basic way to save dictionaries in Python would be to store them as strings in text files.

Which method is used to remove all items from the dictionaries?

Python Dictionary clear() Method The clear() method removes all the elements from a dictionary.

How are namespaces and variable scope different from each other in Python?

Namespaces are collections of different objects that are associated with unique names whose lifespan depends on the scope of a variable. The scope is a region from where we can access a particular object. There are three levels of scopes: built-in (outermost), global, and local.


4 Answers

The solution below provides syntax very close to your requirement, the only difference is that you have to pass to the function environment where the variables are defined explicitly:

x = 10
y = 20

class dump_into_namespace:
    def __init__(self, env, *vars):
        self.vars = dict([(x, env[x]) for v in vars for x in env if v is env[x]])
    def __getattr__(self, name): return self.vars[name]

o = dump_into_namespace(locals(), x, y)
print o.x, o.y

You can then 'dump' back the variables to your locals (say, in a different function):

>>> locals().update(o.vars)
>>> x
10

EDIT:

Thanks to the suggestion of eyquem this can be even shorter. The idea is to put variables into self.__dict__ of the 'dump' object (note: syntax of update changes here):

class dump_into_namespace:
    def __init__(self, env, *vs):
        vars(self).update(dict([(x, env[x]) for v in vs for x in env if v is env[x]]))

def f():
    x = 10
    y = 20
    return dump_into_namespace(locals(), x, y)

o = f() 
print o.x, o.y 
globals().update(vars(o))
print x
like image 109
piokuc Avatar answered Sep 24 '22 02:09

piokuc


You have several options to create your 'namespace'. The easiest two are:

  • Create a quick custom class:

    class Namespace(object):
        def __init__(self, **kw):
            self.__dict__.update(kw)
    
    def dump_into_namespace(**kw):
        return Namespace(**kw)
    

    Call with dump_into_namespace(a='a', b='b', c='c'); this takes an arbitrary number of keyword arguments.

  • Use a collections.namedtuple class:

    from collections import namedtuple
    
    Namespace = namedtuple('Namespace', 'a b c')
    
    def dump_into_namespace(a, b, c):
        return Namespace(a, b, c)
    

    Call with dump_into_namespace('a', 'b', 'c'); this only takes a fixed number of arguments, but your dump_into_namespace() function could provide defaults.

What you call 'dot notation' is really just attribute access.

like image 35
Martijn Pieters Avatar answered Sep 23 '22 02:09

Martijn Pieters


To be honest, the easiest way is just to assign them:

e.a = a
e.b = b
e.c = c

You can't really do it more dynamically, because a variable doesn't know its own name. You would have to pass them as keyword arguments, in which case you can just update the namespace's __dict__ directly:

def dump_into_namespace(e, **kwargs):
    e.__dict__.update(kwargs)

and you would have to call it as:

dump_into_namespace(e, a=a, b=b, c=c)
like image 29
Daniel Roseman Avatar answered Sep 23 '22 02:09

Daniel Roseman


EDIT:

piokuc's answer inspired me to take account of the environnement

My solution updates self._dict_ so that there is no need to define a special function __getattr__ : the objects passed to the function become real attributes, their names belongs to the created object's dictionary.

def dump_into_ns(env,*x):
    class A:
        def __init__(self,*y):
            vars(self).update((n,o) for n,o in env.items()
                              if o in y)
    return A(*x)


a = 19
b = 'Monday'
c = 'Wednesday'


def ftry(x,y):
    palat = 'obastey'
    a = x -1
    b = y +100
    c = x*y -8
    return dump_into_ns(locals(),a,b,c)



h = dump_into_ns(globals(),a,b,c)
print "h.__dict__ ==",h.__dict__
print '"a" in h.__dict__ ==',"a" in h.__dict__,"  h.a ==",h.a
print '"b" in h.__dict__ ==',"b" in h.__dict__,"  h.b ==",h.b
print '"c" in h.__dict__ ==',"c" in h.__dict__,"  h.c ==",h.c
print

e = ftry(20,50)
print "e.__dict__ ==",e.__dict__
print '"a" in e.__dict__ ==',"a" in e.__dict__,"  e.a ==",e.a
print '"b" in e.__dict__ ==',"b" in e.__dict__,"  e.b ==",e.b
print '"c" in e.__dict__ ==',"c" in e.__dict__,"  e.c ==",e.c
print

print 'h.a == e.a  : ',h.a==e.a
print 'h.b == e.b  : ',h.b==e.b
print 'h.c == e.c  : ',h.c==e.c

result

h.__dict__ == {'a': 19, 'c': 'Wednesday', 'b': 'Monday'}
"a" in h.__dict__ == True   h.a == 19
"b" in h.__dict__ == True   h.b == Monday
"c" in h.__dict__ == True   h.c == Wednesday

e.__dict__ == {'a': 19, 'c': 992, 'b': 150}
"a" in e.__dict__ == True   e.a == 19
"b" in e.__dict__ == True   e.b == 150
"c" in e.__dict__ == True   e.c == 992

h.a == e.a  :  True
h.b == e.b  :  False
h.c == e.c  :  False

In a sense the set of attributes of an object also form a namespace.

http://docs.python.org/2/tutorial/classes.html

like image 40
eyquem Avatar answered Sep 23 '22 02:09

eyquem