这个问题在这里已经有了答案:如何动态创建变量? [重复] (8个回答) 7年前关闭。
如何在 Python 中动态设置局部变量(变量名是动态的)?
locals()
只是调用 PyFrame_FastToLocals 来创建当前值的 dict 视图。如果您使用 ctypes
在当前帧 (sys._getframe(0)
) 上调用 PyFrame_LocalsToFast,您可以基于此 dict 动态更新快速本地。
与已经发布的其他答案相反,您不能直接修改 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 locals()
的 C 实现中(从函数内部调用)创建一个从局部变量的当前值初始化的普通字典。在每个函数中,对 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()
返回的字典的结果。
其他人建议分配给 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()
(并借此机会覆盖您的函数实际需要的变量)?
(只是给其他人谷歌搜索的快速说明)
好的,所以修改 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
您可以直接修改
locals()
:
locals()['foo'] = 'bar'
但更好的方法是拥有一些将所有动态变量名称保存为字典键的字典:
d = {}
for some in thing:
d[some] = 'whatever'
locals()
Note The contents of this dictionary should not be modified; changes may not affect the values of local and free variables used by the interpreter.
locals()['foo'] = 'bar'
适用于 python 2.7 和 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()
...
这是一个相当笨拙/人为的例子,但如果有很多当地人或者你仍在原型制作过程中,这个模式就会变得有用。大多数情况下,我只是对复制或移动所有数据存储以处理回调委托等感到痛苦。
您可以使用本地字典并将所有动态绑定作为项目放入字典中。然后知道了这样一个“动态变量”的名称,您可以使用名称作为键来获取它的值。
假设我们有以下字典:
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
不定期副业成功案例分享
locals()
的返回值是 CPython 2.x 和 3.x 中的标准字典,可以照常更改(但更改传播回本地范围)。 2. 访问类和实例名称空间并不总是涉及字典查找。有几个例外,包括定义__slots__
的类的实例。locals()
会返回同一个字典并在每次调用它时覆盖现有的键,所以因为我混合了对locals()
的多次调用并打印了它最初返回的字典对我来说,就好像它没有改变一样。我已经在答案中解释了这个可能的陷阱。谢谢。locals()
字典外无法访问它,并且无法确保您没有覆盖或隐藏另一个本地人或甚至是一个全球名称。使用dict
可以安全地将任何字符串存储为键。exec
或覆盖locals()
一个人将承担您提到的事情的风险(例如覆盖事情)。如果可以确定将变量加载到局部变量以及名称是什么,则可以稍后使用这些变量,如果它们没有预先定义,编译器就会出现问题。我个人认为没什么大不了的,总是可以重写像for = 'breaking for keyword'
这样的 gobals,而无需覆盖本地人的帮助。我想我不欣赏真正的问题或什么...