当前位置: 首页 > news >正文

python可以不对变量初始化_Python的诡异陷阱

编程的人,特别是学过c语言,使用过很长时间c的人,都会觉得,python这种语言跟matlab一样,没什么内涵,很easy。一开始也是这么想的,那是慢慢的,越来越觉得,人生苦短,我用python的理念其实不对。python完成一些小制作是很easy的事情,但是真正要成为一种工具,其实还是要考虑很多事情。近期实习的过程中,这种感觉越来越强烈了。

python看起来简单,其实内涵很复杂。有人说c很难,有指针;c++很难,要自己管理内存。其实,这种能看到的东西就不算难,掌握了就好,难的是隐藏起来的东西。就像风险,内被预计到的,都不是风险。

1.函数内部引用的错误

va = 100

def df_f():

print va

va = 9

print va

df_f()        没有接触过的同学,恐怕觉得上面这段代码是没有问题的,因为python会自动去引用全局变量。

首先,我们要清楚一点,python变量查找的顺序是

Python的作用域解析是基于LEGB规则,分别是Local、Enclosing、Global、Built-in。也就是说,python会先查找函数内部的局部变量。那么问题来了,第一个print va的时候,寻找局部变量的时候能找到吗?答案是能!

这是因为,python在函数定义的时候,所有的变量初始化已经完成了,换句话说,我们定义函数,而没有调用的时候,下面的va = 9这句话已经定义了一个va变量。当我们调用函数的时候,第一个print va会去寻找va局部变量,幸运的是,他找到了va这个局部变量,但是,当时这个变量还没有赋值,只是被预留了,所以,最后就是出现了错误:

UnboundLocalError: local variable 'va' referenced before assignment

再来看一段:

va = 100

def df_f():

va = 20

print va

va = 9

print va

df_f()

print va

我们看到结果是这样的:

D:\Anaconda2\python.exe E:/academic/funny/python_one_one_code/cl_4/hh.py

20

9

100

Process finished with exit code 0

和我们的想法一下,va在函数里面是局部变量,并不会改变外面这个值。

当我们真的想一开始就用外面这个va怎么办?这个时候就要用global申明。

va = 100

def df_f():

global va

print va

va = 9

print va

df_f()

print vaD:\Anaconda2\python.exe E:/academic/funny/python_one_one_code/cl_4/hh.py

100

9

9

Process finished with exit code 0

可以看到,全局变量va被我们在函数内部改变了。

还有更加夸张的例子:

import random

def func(ok):

if ok:

a = random.random()

else:

import random

a = random.randint(1, 10)

return a

func(True)大家可以自己运行、思考一下。

2.把上面那句话:函数在定义的时候就开辟空间了延伸一下

def f(lst = []):

lst.append(1)

return lst

print f()

print f()我们按照上面的逻辑,在函数定义的时候,变量们都被开辟了空间,那么,这里的lst = [ ]其实也是被开辟空间了,所以,上面的函数运行的时候,append其实是同一个list,所以,结果是这样的:

D:\Anaconda2\python.exe E:/academic/funny/python_one_one_code/cl_4/hh.py

[1]

[1, 1]

Process finished with exit code 0

那么我们怎么避免这样的情况呢?

def f(lst=None):

if lst == None:

lst = []

lst.append(1)

return lst

print f()

print f()D:\Anaconda2\python.exe E:/academic/funny/python_one_one_code/cl_4/hh.py

[1]

[1]

Process finished with exit code 0

这个时候就和我们想要的结果一样了。

所以,尽可能不要在定义函数初始化变量的时候,直接默认定义为mutable这样的变量,当然,个人更加喜欢说,是reference这样的变量。

3. 以为的等价,并不等价

还是list这种reference带来的问题:

>>> x=[1];print id(x);x=x+[2];print id(x)

4357132800

4357132728

>>> x=[1];print id(x);x+=[2];print id(x)

4357132800

4357132800x = x + [2] 会改变x的引用,我们可以认为,是重新计算了一个值,然后放到了一个新的内存空间。而后者,则是放在原始的空间中。当然,这种对于value类型其实是一样的。

4.一个元素的tuple

(3),你以为这是一个tuple?不,他就是一个int,(3,)这样才是一个tuple。

print type((1))

print type((1,))D:\Anaconda2\python.exe E:/academic/funny/python_one_one_code/cl_4/hh.py

Process finished with exit code 0

本文同步分享在 博客“钱塘小甲子”(CSDN)。

如有侵权,请联系 support@oschina.cn 删除。

本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。

相关文章:

  • python怎么绘制图例_用Python绘制图例
  • centos7安装mysql5.7.23_centos7.1上安装Mysql5.7.23
  • java客户端_大家都是怎么发布Java客户端程序的?难道让用户自己装JRE?
  • java 加载jar_java – 在运行时加载jar
  • java ant linux_linux下ant的安装
  • java获取数据库信息_java获取数据库的库、表、字段信息
  • java jpanel 布局管理器,JPanel和Java布局管理器
  • java 验证码识别 类库_iCaptcha
  • java调用wsdl证书错误_java调用.net web service服务,报证书错误
  • mysql 联表删除limit_MySQL联结多表更新和删除_mysql
  • mysql数据库备份总结_mysql中mysqlhotcopy备份数据库总结
  • java 反射 api_七分钟理解 Java 的反射 API
  • java 导入dbf文件_用java怎么实现批量导入dbf文件(从dbf文件导入到sqlserver2008中)到sqlserver2008...
  • md5算法 java_MD5算法[ java 实现]
  • java获取指定日期_Java 获取指定日期的前一周
  • @jsonView过滤属性
  • CoolViewPager:即刻刷新,自定义边缘效果颜色,双向自动循环,内置垂直切换效果,想要的都在这里...
  • C语言笔记(第一章:C语言编程)
  • HashMap ConcurrentHashMap
  • Ruby 2.x 源代码分析:扩展 概述
  • Vue源码解析(二)Vue的双向绑定讲解及实现
  • webpack+react项目初体验——记录我的webpack环境配置
  • 回顾 Swift 多平台移植进度 #2
  • 开年巨制!千人千面回放技术让你“看到”Flutter用户侧问题
  • 盘点那些不知名却常用的 Git 操作
  • 腾讯大梁:DevOps最后一棒,有效构建海量运营的持续反馈能力
  • 写给高年级小学生看的《Bash 指南》
  • 在 Chrome DevTools 中调试 JavaScript 入门
  • 正则表达式
  • k8s使用glusterfs实现动态持久化存储
  • ​​​​​​​​​​​​​​Γ函数
  • ​520就是要宠粉,你的心头书我买单
  • ​批处理文件中的errorlevel用法
  • ​软考-高级-信息系统项目管理师教程 第四版【第19章-配置与变更管理-思维导图】​
  • #NOIP 2014# day.1 T2 联合权值
  • (2/2) 为了理解 UWP 的启动流程,我从零开始创建了一个 UWP 程序
  • (4)STL算法之比较
  • (八)c52学习之旅-中断实验
  • (八)Flask之app.route装饰器函数的参数
  • (附源码)ssm高校运动会管理系统 毕业设计 020419
  • (附源码)计算机毕业设计ssm-Java网名推荐系统
  • (附源码)计算机毕业设计SSM保险客户管理系统
  • **CI中自动类加载的用法总结
  • ./indexer: error while loading shared libraries: libmysqlclient.so.18: cannot open shared object fil
  • .NET MVC第三章、三种传值方式
  • /etc/sudoer文件配置简析
  • [2016.7 day.5] T2
  • [AutoSar NVM] 存储架构
  • [bzoj2957]楼房重建
  • [C# 基础知识系列]专题十六:Linq介绍
  • [C#]winform部署yolov5-onnx模型
  • [CentOs7]图形界面
  • [DAU-FI Net开源 | Dual Attention UNet+特征融合+Sobel和Canny等算子解决语义分割痛点]
  • [github全教程]github版本控制最全教学------- 大厂找工作面试必备!
  • [JavaWeb学习] Spring Ioc和DI概念思想