[ Python ]求教大佬关于 locals()动态生成变量

2018-01-06 19:30:41 +08:00
 cnaol
在函数外一切使用正常

#生产变量如 lis0 lis1 默认空列表 并打印出来
for i in range(0,11):
locals()['lis%d' % i] = []
print('lis%d : %s' % (i,eval('lis%d' % i)))

#单独给变量 lis3 append(6)
lis3.append(6)

#全部变量 append(2)打印 lis0~lis10 变量
for i in range(0,11):
eval('lis%d' % i).append(2)
print('lis%d : %s' % (i,eval('lis%d' % i)))

但是把他包裹在函数中使用
def func():
上面的代码
func()
在 lis3.append(6)这里就报错:变量名没定义

但是当我使用 eval('list3').append(6)就正常了




想请问是为什么以及该如何解决 谢谢
4027 次点击
所在节点    Python
12 条回复
ballshapesdsd
2018-01-06 19:47:11 +08:00
你这种写法,用个 list 不好吗?我看你是在刁难我胖虎
ballshapesdsd
2018-01-06 20:00:25 +08:00
你试试把 locals 改成 globals 可以跑出来,或者在函数外面定义一个 lis3,也不会报错,但是结果有问题。只能说 lis3 不完全等于 eval('lis3')
ballshapesdsd
2018-01-06 20:19:53 +08:00
ballshapesdsd
2018-01-06 20:26:38 +08:00
https://docs.python.org/2/library/functions.html?highlight=locals#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
cnaol
2018-01-06 21:05:08 +08:00
@ballshapesdsd 我试过 globals 确实可以跑出来 但是这样是全局的变量 容易造成污染 谢谢你的回答
xpresslink
2018-01-06 23:02:34 +08:00
通常的 Python 实现中,locals()返回的只是菊部变量字典的 copy,和 globals()不一样的。
在 python 中变量只是对象的标签,只是引用而已,所以你这么蛋疼的需求并无什么实质意义。
老老实实用个 list 或 dict 就行了,引用起来更方便。
要是实在想这么弄,还非要搞菊部的。
直接 exec('lis%s=[]' % i )
lrxiao
2018-01-07 00:26:21 +08:00
很简单
locals 修改的是当前栈帧
但是 bytecode 这里用到的 lis3 是引用的函数的__code__.co_names / LOAD_GLOBAL
况且本来就不该修改 locals
albert2x
2018-01-07 02:28:52 +08:00
试试深拷贝
introom
2018-01-07 11:09:23 +08:00
=locals= is different in that the underlying implementation is not based on hash dict. instead, for speed purpose, it's stored as a c array associated with the frame object. cf. https://github.com/python/cpython/blob/master/Python/ceval.c#L878 for a clear picture. I don't recommend modifying the local variables (and the enclosure ones), but if you really want, you can import ctypes and do the hack.
thautwarm
2018-01-07 13:22:27 +08:00
为什么会 NameError,这是符号表加载的问题。

locals()设置新 name 是无意义的,虽然每一次在一个作用域拿出的 locals()都是同一个引用,但是导入符号并非直接使用 locals(),也就是说你对它的修改,如果是修改 mutable 对象的内部还好,直接改 immutable 自然是无效的。

Python 确定从哪里加载符号,代码编译到字节码时就确定了。既然编译时找不到 lis3 的定义,自然就认为它来自 globals()里面。而你在代码解释时才修改 locals(),那么犯错的原因,如下有俩

1. locals()不是 func 作用域加载符号所用的符号表
2. lis3 被预先认为是定义在 globals()里的。



P.S 关于 locals()的行为。
locals()其中一部分类似于一个作用域符号管理结构 S 上的 view。另一部分,locals()应该也有一个"固有成分",当你对 locals()进行__setitem__操作,并不是没有起效果,而是因为 locals 的__getitem__是有限搜索 S 的 item,没有的话再搜索 locals()的"固有成分"。

def g(x=20):
d = locals()
locals()['x'] = 10
print(locals()['x'])
print(d is locals())
g()
# => 20
# True

def g():
locals()['x'] = 10
print(locals()['x'])
g()
# 10

以上。。
linlin12914
2018-01-08 11:37:07 +08:00
@xpresslink 菊。。。菊部?
xpresslink
2018-01-08 12:01:43 +08:00
@linlin12914 最鄙视就是你这种人,就知道盯着菊部看:-)

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/420660

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX