python把局部变量赋值给全局变量_局部变量不赋初值

python把局部变量赋值给全局变量_局部变量不赋初值理解的都没问题。但我想聊聊出现这种情况的原因。在讲原因之前,需要先知道python中变量的搜索顺序,这个顺序是LGB(不考虑闭包情况)即local本地,global全局,builtin内建。比如:a=1deftest():a=3print(a)test()函数内声明了局部变量a,在打印中使用,在本地环境中命中,因此使用的是3。也许你会问这个知识点我早就知道了,这和本问题有什么关…

大家好,又见面了,我是你们的朋友全栈君。如果您正在找激活码,请点击查看最新教程,关注关注公众号 “全栈程序员社区” 获取激活教程,可能之前旧版本教程已经失效.最新Idea2022.1教程亲测有效,一键激活。

Jetbrains全家桶1年46,售后保障稳定

理解的都没问题。但我想聊聊出现这种情况的原因。在讲原因之前,需要先知道python中变量的搜索顺序,这个顺序是 LGB (不考虑闭包情况)即local本地,global全局,builtin内建。比如:

a = 1

def test():

a = 3

print(a)

test()

函数内声明了局部变量 a ,在打印中使用,在本地环境中命中,因此使用的是 3。

也许你会问这个知识点我早就知道了,这和本问题有什么关系呢?

有的,难道你不觉得奇怪吗?报错是变量未初始化,而不是变量未定义。

题目中函数内 c= c+1 就已经表明了声明的变量 c 是属于局部变量的。 按理说,先执行赋值语句右侧,而此时 c 并没有声明,应该在全局环境命中才对啊。所以想象中的结果应该是局部变量 c = 2 而全局变量的 c 保持原值。

但是,这只都是想当然。讲了这么多其实我是想引出,python虽然是动态语句,但它还是会对代码做扫描工作的,会有收集有用的静态信息。函数的应该信息会放在 code 对象中,里面的信息就包含了局部变量名称的集合,可以通过 co_varnames 得到,如下:

c = 1

def test():

c= c+1

a = 3 # 另一个局部变量

print(c)

print(test.__code__.co_varnames) # (‘c’, ‘a’)

因此,函数test在执行前,变量 c 就已经被声明在局部变量环境中了,而不是我们自认为的当赋值语句运行后才会在局部变量里。于是,这就导致了报错信息是变量未初始化而不是变量未定义。

====== 分割线 =========

题主评论要求:

关于变量的初始化,定义,创建这三者关系,能帮忙疏导一下理解吗?

这三个意思基本差不多,没必要分得太开。把变量环境理解成一个字典 name_env = dict() 其实就很好理解了(事实上python底层也确实是这样处理的)。对于在这个环境内要创建一个名为 a 的变量,就可以是 name_env[‘a’] = value 的形式了。

这个过程也就是赋值语句形如 a = value 时会调用赋值的指令 STORE_NAME 。我们看一下这个赋值过程你就理解了。

这部分代码在 ceval.c 中,详见 ceval.c

TARGET(STORE_NAME) {

PyObject *name = GETITEM(names, oparg);

PyObject *v = POP();

PyObject *ns = f->f_locals;

int err;

if (ns == NULL) {

PyErr_Format(PyExc_SystemError,

“no locals found when storing %R”, name);

Py_DECREF(v);

goto error;

}

if (PyDict_CheckExact(ns))

err = PyDict_SetItem(ns, name, v);

else

err = PyObject_SetItem(ns, name, v);

Py_DECREF(v);

if (err != 0)

goto error;

DISPATCH();

}

代码不多,可以逐个分析下,第一行获得的 name 就是赋值语句 a = value 的 a,a以python类型 str 形式存在。第二行 v 从栈中获取,也就是 value 的值。第三行 ns 是从帧对象中获得局部变量环境(大多数情况下是个字典类型,如果帧环境不在函数或类中,取得的是全局变量环境)。PyDict_SetItem(ns, name, v); 和 PyObject_SetItem(ns, name, v); 就可以理解为 ns[name] = v 和 setattr(ns, name, v) 了,创建过程就是这样了。

变量究竟是创建还是初始化还是覆盖已有的变量值,其实底层并不关心。

回到本地中,本地变量的符号表会保存在静态信息里面,我猜测搜索变量时有优先去静态信息中得到信息,来更快的知道变量应该是在局部还是全局中查找吧。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/206693.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • idea编辑器中文乱码_idea控制台中文乱码解决不了

    idea编辑器中文乱码_idea控制台中文乱码解决不了配置Intellij的配置文件打开Intellij的根目录,找到下图的两个文件(根据你的系统是32位或64位选择其中一个配置文件),在配置文件中添加:-Dfile.encoding=UTF-8配置项目编码及IDE编码进入settings,选择FileEncodings,把IDEEncoding和ProjectEncoding配置为UTF-8,同时将下面的Defaultencoding

    2022年8月29日
    2
  • 最新最全Golang面试题(精通篇)

    最新最全Golang面试题(精通篇)Golang面试问题汇总通常我们去面试肯定会有些不错的Golang的面试题目的,所以总结下,让其他Golang开发者也可以查看到,同时也用来检测自己的能力和提醒自己的不足之处,欢迎大家补充和提交新的面试题目.1.Golang中除了加Mutex锁以外还有哪些方式安全读写共享变量Golang中Goroutine可以通过Channel进行安全读写共享变量,还可以通过原子性操作进行.2.无缓冲Chan的发送和接收是否同步ch:=make(chanint)无缓冲的channel由于没有缓

    2022年6月25日
    22
  • parentNode,firstChild,parentNode,nextSibling;

    parentNode,firstChild,parentNode,nextSibling;UntitledDocument                  functiontest1(){            varnode=document.getElementById(“imgid2”);             varpimg=node.parentNode.firstChild;

    2022年7月15日
    11
  • linux清除文件内容 >,Linux清除文件内容的几种方法[通俗易懂]

    linux清除文件内容 >,Linux清除文件内容的几种方法[通俗易懂]#清空或删除大文件内容的五种方法:#法一:通过重定向到Null来清空文件内容$>test.sh#法二:使用‘true’命令重定向来清空文件$true>test.sh#可通过下列命令来查看文件容量是否为0$du-htest.sh0test.sh#法三:使用cat/cp/dd实用工具及/dev/null设备来清空文件$cat/dev/null…

    2022年7月26日
    6
  • 亿图图示mac版激活码 csdn(JetBrains全家桶)2022.01.24

    (亿图图示mac版激活码 csdn)好多小伙伴总是说激活码老是失效,太麻烦,关注/收藏全栈君太难教程,2021永久激活的方法等着你。IntelliJ2021最新激活注册码,破解教程可免费永久激活,亲测有效,下面是详细链接哦~https://javaforall.net/100143.html1TCF2R91JZ-eyJsaWNlbnNlSW…

    2022年3月31日
    269
  • 客户端网页编程导向

    客户端网页编程导向客户端网页编程导向

    2022年4月22日
    54

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号