动态设置局部变量

时间:2011-11-06 17:03:49

标签: python dynamic

如何在Python中动态设置局部变量?

(变量名称是动态的)

更新:我知道这不是一个好的做法,这些言论是合法的,但这并不是一个坏问题,只是一个更理论的问题 - 我不是看看为什么这证明了downvotes。

7 个答案:

答案 0 :(得分:70)

与已发布的其他答案相反,您无法直接修改locals()并希望它可以正常工作。

>>> def foo():
    lcl = locals()
    lcl['xyz'] = 42
    print(xyz)


>>> foo()

Traceback (most recent call last):
  File "<pyshell#6>", line 1, in <module>
    foo()
  File "<pyshell#5>", line 4, in foo
    print(xyz)
NameError: global name 'xyz' is not defined

修改locals()未定义。在locals()globals()相同的函数之外它将起作用;在一个函数中,通常不起作用。

使用字典,或在对象上设置属性:

d = {}
d['xyz'] = 42
print(d['xyz'])

或者如果您愿意,请使用课程:

class C: pass

obj = C()
setattr(obj, 'xyz', 42)
print(obj.xyz)

修改: 访问不是函数的命名空间中的变量(所以模块,类定义,实例)通常通过字典查找来完成(正如Sven在注释中指出的那样存在异常,例如定义__slots__的类)。函数本地可以针对速度进行优化,因为编译器(通常)预先知道所有名称,因此在您调用locals()之前不会有字典。

在Python的{C}实现中locals()(从函数内部调用)创建一个从局部变量的当前值初始化的普通字典。在每个函数中,对locals()的任何数量的调用都将返回相同的字典,但每次调用locals()都会使用局部变量的当前值更新它。这可能会给人一种印象,即对字典元素的赋值会被忽略(我原来写的就是这种情况)。从locals()返回的字典中对现有键的修改因此仅持续到下一次调用同一范围内的locals()

在IronPython中,事情有点不同。在其中调用locals()的任何函数都使用字典作为其局部变量,因此对局部变量的赋值会更改字典,并且对字典的赋值会更改变量 BUT ,只有在您明确调用{{ 1}}在这个名字下面。如果您将另一个名称绑定到IronPython中的locals()函数,则调用它会为您提供绑定名称的范围的局部变量,并且无法通过它访问函数本地:

locals

这一切都可以随时改变。唯一可以肯定的是,您不能依赖于分配给>>> def foo(): ... abc = 123 ... lcl = zzz() ... lcl['abc'] = 456 ... deF = 789 ... print(abc) ... print(zzz()) ... print(lcl) ... >>> zzz =locals >>> foo() 123 {'__doc__': None, '__builtins__': <module '__builtin__' (built-in)>, 'zzz': <built-in function locals>, 'foo': <function foo at 0x000000000000002B>, '__name__': '__main__', 'abc': 456} {'__doc__': None, '__builtins__': <module '__builtin__' (built-in)>, 'zzz': <built-in function locals>, 'foo': <function foo at 0x000000000000002B>, '__name__': '__main__', 'abc': 456} >>> 返回的字典的结果。

答案 1 :(得分:23)

其他人建议分配给locals()。这在函数内部不起作用,其中使用LOAD_FAST操作码访问本地,除非在函数的某处有exec语句。为了支持这个语句,它可以创建在编译时未知的新变量,然后Python被强制在函数中按名称访问局部变量,因此写入locals()有效。 exec可能超出了执行的代码路径。

def func(varname):
    locals()[varname] = 42
    return answer           # only works if we passed in "answer" for varname
    exec ""                 # never executed

func("answer")
>>> 42

注意:这仅适用于Python 2.x.他们在Python 3中摒弃了这种愚蠢,其他实现(Jython,IronPython等)也可能不支持它。

但是,这是一个坏主意。如果您不知道他们的名字,您将如何访问变量?可能是locals()[xxx]。那么为什么不使用你自己的字典而不是污染locals()(并且有机会覆盖你的函数实际需要的变量)?

答案 2 :(得分:5)

(只是其他人googlin的快速说明)

好的,所以修改locals() is not the way to go(同时修改globals() is supposed to work)。与此同时,exec 可能是,但速度非常慢,因此,与正则表达式一样,我们可能首先要compile()它:

# var0 = 0; var1 = 1; var2 = 2
code_text = '\n'.join( "var%d = %d" % (n, n) for n in xrange(3) )

filename = ''
code_chunk = compile( code_text, filename, 'exec' )

# now later we can use exec:
exec code_chunk # executes in the current context

答案 3 :(得分:3)

我已经花了最后几个小时,我想,试图破解缺少功能关闭,我想出了这个,这可能会有所帮助:

common_data = ...stuff...
def process(record):
    ...logic...

def op():
    for fing in op.func_dict: # Key line number 1
        exec(fing + " = op.func_dict[fing]") # Key line number 2

    while common_data.still_recieving:
        with common_data._lock:
            if common_data.record_available:
                process(common_data.oldest_record)
        time.sleep(1.0)

op.func_dict.update(locals()) # Key line number 3
threading.Thread(target = op).start()

...

这是一个非常沉重/做作的例子,但是如果有很多当地人或者你仍然处于原型制作过程中,这种模式就会变得有用。大多数情况下,我只是为了处理回调代表等而被复制或移动的所有数据存储都很痛苦。

答案 4 :(得分:2)

您可以直接修改locals()

locals()['foo'] = 'bar'

但更好的方法是使用一些dict将所有动态变量名称保存为字典键:

d = {}
for some in thing:
    d[some] = 'whatever'

答案 5 :(得分:0)

您可以使用本地字典并将所有动态绑定作为项目放入字典中。然后知道这样一个“动态变量”的名称,您可以使用名称作为键来获取其值。

答案 6 :(得分:0)

假设我们有以下词典:

DictionaryA = {'No Rating': ['Hobbit', 'Movie C', 'Movie G'],
               'Forget It': ['Avenger', 'Movie B'], 
               'Must See': ['Children of Men', 'Skyfall', 'Movie F'], 
               '3': ['X-Men', 'Movie D'],
               '2': ['Captain America', 'Movie E'], 
               '4': ['Transformers', 'Movie A']} 

我想创建新的词典,如下所示:

NewDictionary1 = {'No Rating': ['Hobbit', 'Movie C', 'Movie G']} 
NewDictionary2 = {'Forget It': ['Avenger', 'Movie B']} 
NewDictionary3 = {'Must See': ['Children of Men', 'Skyfall', 'Movie F']}

oneliner:

dics = [{k:v} for k,v in DictionaryA.iteritems()]

将输出到:

[{'Must See': ['Children of Men', 'Skyfall', 'Movie F']}, {'Forget It': ['Avenger', 'Movie B']}, {'No Rating': ['Hobbit', 'Movie C', 'Movie G']}, {'3': ['X-Men', 'Movie D']}, {'2': ['Captain America', 'Movie E']}, {'4': ['Transformers', 'Movie A']}]

但要精确地声明变量,我们可以选择:

>>> i=0
>>> lcl = locals()
>>> for key,val in DictionaryA.iteritems():
        lcl["Dict" + str(i)] = {key:val}
        i += 1

可以看到前3个Dict变量:

>>> Dict0
{'Must See': ['Children of Men', 'Skyfall', 'Movie F']}
>>> Dict1
{'Forget It': ['Avenger', 'Movie B']}
>>> Dict2
{'No Rating': ['Hobbit', 'Movie C', 'Movie G']}

正如其他人所说,如果你想把它放在一个函数中,你应该把它添加到globals()

>>> glb = globals()
>>> for key,val in DictionaryA.iteritems():
        glb["Dict" + str(i)] = {key:val}
        i += 1