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)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • 2021pycharm激活码3月最新在线激活[通俗易懂]

    2021pycharm激活码3月最新在线激活,https://javaforall.net/100143.html。详细ieda激活码不妨到全栈程序员必看教程网一起来了解一下吧!

    2022年3月14日
    83
  • utf8在mysql占几个字符_utf-8的中文,一个字符占几个字节「建议收藏」

    utf8在mysql占几个字符_utf-8的中文,一个字符占几个字节「建议收藏」https://blog.csdn.net/kindsuper_liu/article/details/80202150英文字母和中文汉字在不同字符集编码下的字节数英文字母:·字节数:1;编码:GB2312字节数:1;编码:GBK字节数:1;编码:GB18030字节数:1;编码:ISO-8859-1字节数:1;编码:UTF-8字节数:4;编码:UTF-16字节数:2;编…

    2022年6月26日
    28
  • 数据结构:静态链表[通俗易懂]

    数据结构:静态链表[通俗易懂]首先我们让数组的元素都是由两个数据域组成,data和cur。也就是说,数组的每一个下标都对应一个data和一个cur。数据域data用来存放数据元素,也就是通常我们要处理的数据;而游标cur相当于单链表中的next指针,存放该元素的后继在数组中的下标。我们把这种用数组描述的链表叫做静态链表。数组的第一个元素,即下标为0的元素的cur就存放备用链表的第一个结点的下标;而数组的最后一个元素

    2025年7月4日
    2
  • Android 查看Android版本的方法

    Android 查看Android版本的方法查看Android版本的方法

    2022年8月6日
    9
  • kindeditor编辑器代码过滤解决方法.

    kindeditor编辑器代码过滤解决方法.原文连接 http www jiaoguoqiang com kindeditorgu 今天遇到一个问题 需要定制化 a 标签中的内容 但是不管如何 debuglink 插件中的代码都没有用 后面发现 查看源码的时候自己加进去的元素被过滤掉了 才猜想应该是编辑器过滤问题 顺着这个思路 真的解决了问题 很多朋友在使用 Kindeditor 编辑器的时候都会遇到这样一个

    2025年7月2日
    4
  • 点击率预估算法:FM与FFM[通俗易懂]

    点击率预估算法:FM与FFM[通俗易懂]点击率预估算法:FFM@(计算广告)[计算广告]点击率预估算法FFM1FM1背景11线性模型12二项式模型2FM21FM基本原理22数据分析23参数个数24计算时间复杂度25梯度26训练时间复杂度2FFM1背景及基本原理2模型与最优化问题21模型22最优化问题23自适应学习率24FFM算法的最终形式3完整算法流程31计算梯度32

    2022年4月30日
    81

发表回复

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

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