动态设置局部变量[重复]

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了动态设置局部变量[重复]相关的知识,希望对你有一定的参考价值。

这个问题在这里已有答案:

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

(变量名称是动态的)

更新:我知道这不是一个好的做法,而且这些言论是合法的,但这不会成为一个不好的问题,只是一个更理论的问题 - 我不明白为什么这有理由支持downvotes。

答案

与已发布的其他答案相反,您无法直接修改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函数,那么调用它会为你提供绑定名称的范围的局部变量,并且无法通过它访问函数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()(并且有可能覆盖你的函数实际需要的变量)?

另一答案

(只是快速记录其他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
另一答案

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

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()

...

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

另一答案

你可以直接修改locals()

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

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

d = 
for some in thing:
    d[some] = 'whatever'
另一答案

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

另一答案

假设我们有以下字典:

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

以上是关于动态设置局部变量[重复]的主要内容,如果未能解决你的问题,请参考以下文章

学习笔记1(三元运算深浅拷贝动态参数全局变量与局部变量set数据类型 )

如何使局部变量(在函数内部)全局[重复]

全局变量 静态变量 局部变量 啥时候创建 啥时候撤销

成员变量和局部变量

Day831.局部变量为什么是线程安全的 -Java 并发编程实战

Day831.局部变量为什么是线程安全的 -Java 并发编程实战