假设我在Python中有几个变量或对象,a
,b
,c
,...
如何轻松将这些变量转储到Python中的命名空间中并在以后恢复它们? (例如,以argparse
将各种变量包装到命名空间中的方式相同。
以下是我想如何将命令转储到命名空间和从命名空间转储的两个示例:
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
# 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
我的第一个问题是:这在Python中是否可行?(请注意,方法dump_into_namespace
不会直接接收变量的名称,至少我可以告诉)。
如果上面的答案是否定的,我怎么能用这样的界面来做呢?
e = dump_into_namespace('a', 'b', 'c')
此外,如何使用字典而不是命名空间来完成此操作?
有一些线程似乎与动态定义变量的点访问相关,但我不认为它们解决了转储变量的问题:
是否有通过点表示法促进此类访问的库?
看起来有一个库支持Python中的点可访问字典,称为Bunch,但我不确定它是否会像我定义的那样支持轻松转储。
答案 0 :(得分: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
class:
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()
函数可以提供默认值。
你所谓的'点符号'实际上只是属性访问。
答案 1 :(得分:5)
下面的解决方案提供的语法非常接近您的要求,唯一的区别是您必须传递到明确定义变量的函数环境:
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的建议,这可能会更短。我们的想法是将变量放入'dump'对象的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
答案 2 :(得分: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)
答案 3 :(得分: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
在某种意义上,对象的属性集也构成了命名空间。