动态设置局部变量[重复]
- 2024-12-12 08:40:00
- admin 原创
- 172
问题描述:
如何在 Python 中动态设置局部变量(变量名是动态的)?
解决方案 1:
与已经发布的其他答案相反,您不能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()
在其内部调用的函数都会使用字典作为其局部变量,因此对局部变量的赋值会更改字典,对字典的赋值也会更改变量,但前提是您明确使用locals()
该名称进行调用。如果您在 IronPython 中将不同的名称绑定到该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}
>>>
这一切随时都可能发生变化。唯一可以保证的是,您不能依赖 所返回的字典赋值结果locals()
。
解决方案 2:
其他人建议将 赋值给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()
(并冒着覆盖函数实际需要的变量的风险)呢?
解决方案 3:
(这只是给其他谷歌用户的一个简短说明)
好吧,修改locals()
不是解决问题的办法(虽然修改globals()
应该可行)。与此同时,exec
可能是,但它的速度太慢了,所以,与正则表达式一样,我们可能compile()
首先要这样做:
# var0 = 0; var1 = 1; var2 = 2
code_text = '
'.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
解决方案 4:
直接修改就可以了locals()
:
locals()['foo'] = 'bar'
但更好的方法是使用一些字典将所有动态变量名称作为字典键来保存:
d = {}
for some in thing:
d[some] = 'whatever'
解决方案 5:
我猜,我花了……几个小时试图解决缺少函数闭包的问题,然后我想出了这个,它可能会有所帮助:
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()
...
这是一个相当笨拙/做作的例子,但如果有很多本地变量或您仍在进行原型设计,这种模式就会变得有用。大多数情况下,我只是对复制或移动所有数据存储以处理回调委托等感到苦恼。
解决方案 6:
您可以使用本地字典,将所有动态绑定作为条目放入字典中。然后,知道此类“动态变量”的名称后,您就可以使用该名称作为键来获取其值。
解决方案 7:
假设我们有以下词典:
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']}
一句话:
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