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

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

理解的都没问题。但我想聊聊出现这种情况的原因。在讲原因之前,需要先知道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)
全栈程序员-站长的头像全栈程序员-站长

相关推荐

  • 大学四年,我把私藏的自学「学习网站/实用工具」都贡献出来了

    大学四年,我把私藏的自学「学习网站/实用工具」都贡献出来了在分享之前,先说说初学者如何学习编程,这个话题想必非常的重要,要学好编程,给你一些学习网站也好、实用工具也好,但前提是你知道如何去学习它。见过很多初学者,以及小鹿我刚开始学习的时候,也是自己瞎摸索,找不到路子,看什么书?看什么资料?编程的方向太多了,如果确定自己的方向?尤其是上大一、大二甚至大三还没有确定自己到底是学习前端还是后天,每天这学一点,那学一块,掌握那么多,没有一门精通的,去面试的时候…

    2022年6月12日
  • 基金指数温度怎么看_指数温度是什么意思

    基金指数温度怎么看_指数温度是什么意思指数基金真的有那么好吗,连巴菲特也给家族制定自己死后把大部分资金都购买指数基金,如何挑选指数基金呢,有许多人推荐指数温度,那么基金指数温度靠谱吗,银行存款利率网小编和大家学习下指数温度查询技巧。基金指数温度靠谱吗指数温度是正态分布值,即当前估值在历史数值的位置占比,指数温度本质上就是以历史预测未来。关于基金指数温度靠谱吗,当然是有一定的参考价值,但也不能完全依靠关于基金指数温度来决定购买。下面我们…

    2022年10月23日
  • DMRS与SRS

    DMRS与SRSSRS作用:SRS分类:SRS配置:如果SRS在某个子帧上发送,则SRS将占据该子帧的最后一个SC-FDMA符号上(DMRS在每个子帧的符号3和10),若最后一个SC-FDMA符号分配给SRS,

    2022年8月5日
  • 产品经理面试题整理

    产品经理面试题整理凡事“预则立,不预则费”。即使你有丰富的产品经验,在面试那种紧张的环境下要面试好也不是一件易事,因为在那种环境下,你要对面试官提出的问题快速反映,快速组织语言,而你又没有经常训练这种能力,想回答好还是很不容易的,如果你经常背一些产品经理的面试题,那你回答的时候就流畅多了,下面将一些常见的产品经理面试题整理下来,需要的小伙伴拿去。下面我们先看看都有什么问题吧以下是上面的问题的具体解析,可能不全面,欢迎大家补充1、介绍一下你自己介绍一下自己的姓名,年龄、毕业院校,工作…

    2022年6月25日
  • java测试类的创建方法_java编写一个类

    java测试类的创建方法_java编写一个类JUnit基础及第一个单元测试实例(JUnit3.8)JUnit基础及第一个单元测试实例(JUnit3.8) 单元测试  单元测试(unittesting) ,是指对软件中的最小可测试单元进行检查和验证。  单元测试不是为了证明您是对的,而是为了证明您没有错误。  单元测试主要是用来判断程序的执行结果与自己期望的结果是否一致。  关键是

    2022年10月17日
  • java中使用Jedis操作Redis实例[通俗易懂]

    java中使用Jedis操作Redis实例[通俗易懂]要想在Java中连接Redis,并进行操作,由两种方式,一种是springdataredis,它是由spring集成的,不支持集群,一种是官方推荐的jedis,支持集群,其他功能差不多一样,这里我们介绍jedis操作实例,以下是使用Jedis的具体步骤:1、如果是在Maven项目中,在pom.xml中增加如下语句,如果不是Maven项目下载包导入项目即可:…

    2022年9月9日

发表回复

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

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