10

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

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.

4

4 回答 4

6

下面的解决方案提供的语法非常接近您的要求,唯一的区别是您必须传递给显式定义变量的函数环境:

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

然后,您可以将变量“转储”回本地人(例如,在不同的函数中):

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

编辑:

感谢 eyquem 的建议,这可以更短。想法是将变量放入self.__dict__“转储”对象中(注意:此处更新更改的语法):

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
于 2013-02-15T21:44:56.177 回答
5

您有多种选择来创建您的“命名空间”。最简单的两个是:

  • 创建一个快速的自定义类:

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

    dump_into_namespace(a='a', b='b', c='c')用;调用 这需要任意数量的关键字参数。

  • 使用一个collections.namedtuple

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

    dump_into_namespace('a', 'b', 'c')用;调用 这只需要固定数量的参数,但您的dump_into_namespace()函数可以提供默认值。

您所说的“点表示法”实际上只是属性访问。

于 2013-02-15T21:31:43.093 回答
4

老实说,最简单的方法就是分配它们:

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

你真的不能更动态地做它,因为一个变量不知道它自己的名字。您必须将它们作为关键字参数传递,在这种情况下,您可以直接更新命名空间__dict__

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

你必须把它称为:

dump_into_namespace(e, a=a, b=b, c=c)
于 2013-02-15T21:32:58.627 回答
2

编辑:

piokuc 的回答启发我考虑环境

我的解决方案更新self._ dict _以便无需定义特殊函数__getattr__:传递给函数的对象成为真正的属性,它们的名称属于创建对象的字典。

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

结果

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

从某种意义上说,对象的属性集也形成了命名空间。

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

于 2013-02-15T22:07:38.560 回答