Python基础系列讲解—动态类型语言的特点
前言
在C语言中变量所分配到的地址是内存空间中一个固定的位置,当我们改变变量值时, 对应内存空间中的值也相应改变。在Python中变量存储的机制是完全不一样的,当给一个变量赋值时首先解释器会给这个值分配内存空间,然后将变量指向这个值的地址,那么当我们改变变量值的时候解释器又会给新的值分配另一个内存空间,再将变量指向这个新值的地址,所以和C语言相比,在Python中改变的是变量所指向的地址,而内存空间中的值是固定不变的。
例程介绍
我们可以通过id方法查看变量的内存地址的方式来进行验证。以下先以Python的int类型为例,可以看到执行 i += 1 后,变量i的内存地址会发生变化,事实上 i += 1 并不是在原有变量i的地址上加1,而是重新创建一个值为6的int对象,变量i则引用了这个新的对象,因此当变量i和变量j的值相同时会指向同个内存地址 。同样以Python的float 类型为例也验证了这个变量存储管理的机制。
#int
i = 5
print "i ---> ",i
print "id(i) ---> ",hex(id(i))
i += 1
print "i ---> ",i
print "id(i) ---> ",hex(id(i))
j = 5
print "j ---> ",j
print "id(j) ---> ",hex(id(j))
______________________
i ---> 5
id(i) ---> 0xa26f880
i ---> 6
id(i) ---> 0xa26f874
j ---> 5
id(j) ---> 0xa26f880
#float
i = 1.5
print "i ---> ",i
print "id(i) ---> ",hex(id(i))
i += 1
print "i ---> ",i
print "id(i) ---> ",hex(id(i))
j = 1.5
print "j ---> ",j
print "id(j) ---> ",hex(id(j))
______________________
i ---> 1.5
id(i) ---> 0x9e86c8c
i ---> 2.5
id(i) ---> 0x9e86cac
j ---> 1.5
id(j) ---> 0x9e86c8c
接下来以Python的list类型为例,可以看到list变量i在append之后,仍然指向同一个内存地址,而j、k的值虽然相同,但是指向的内存地址却不同。我们通过j = k 的赋值语句可以让j、k指向同一个内存地址,对j、k任意一个list变量进行修改,都会影响另外一个list变量的值。比如j变量append(4)时,同时对k变量也产生影响,查看j、k的内存地址,发现它们仍然指向了同个内存地址。
#list
i = [1, 2, 3]
print "i ---> ",i
print "id(i) ---> ",hex(id(i))
i.append(4)
print "i ---> ",i
print "id(i) ---> ",hex(id(i))
j = [1.5, 2.5, 3.5]
print "j ---> ",j
print "id(j) ---> ",hex(id(j))
k = [1.5, 2.5, 3.5]
print "k ---> ",j
print "id(k) ---> ",hex(id(k))
j = k
print "j ---> ",j
print "id(j) ---> ",hex(id(j))
print "k ---> ",j
print "id(k) ---> ",hex(id(k))
j.append(4)
print "j ---> ",j
print "id(j) ---> ",hex(id(j))
print "k ---> ",j
print "id(k) ---> ",hex(id(k))
______________________
i ---> [1, 2, 3]
id(i) ---> 0xb73fa1acL
i ---> [1, 2, 3, 4]
id(i) ---> 0xb73fa1acL
j ---> [1.5, 2.5, 3.5]
id(j) ---> 0xb6fed06cL
k ---> [1.5, 2.5, 3.5]
id(k) ---> 0xb6fed04cL
j ---> [1.5, 2.5, 3.5]
id(j) ---> 0xb6fed04cL
k ---> [1.5, 2.5, 3.5]
id(k) ---> 0xb6fed04cL
j ---> [1.5, 2.5, 3.5, 4]
id(j) ---> 0xb6fed04cL
k ---> [1.5, 2.5, 3.5, 4]
id(k) ---> 0xb6fed04cL
刚才讲到Python的int类型的两个变量值相同时,Python解释器并不会分别为两个变量申请内存,而是优化的将他们指向同个内存地址。但这里有个例外的情况,当变量s1和s2 存储20个char时,Python仍然将两个变量引用指向了相同内存地址,但当存储为21个char时,Python为s2开辟了新的内存。厦门叉车多少钱
s1 = 'a' * 20
s2 = 'a' * 20
print hex(id(s1)), hex(id(s2))
0xb7075320L 0xb7075320L
s1 = 'a' * 21
s2 = 'a' * 21
print hex(id(s1)), hex(id(s2))
0xb70752f0L 0xb7075350L
总结
根据以上的这些例子,我们可以知道Python中的对象分为可变类型和不可变类型,列表、字典是可变类型,而整数、浮点、短字符串、元组等是不可变类型。可变类型的变量赋值与我们了解的C语言机制相同,而不可变类型的变量赋值时,实际上是重新创建一个不可变类型的对象,并将原来的变量重新指向新创建的对象,当然如果没有其他变量引用原有对象时,原有对象就会被回收。这也是Python作为动态类型语言的特点,即变量不需要预先声明类型,当变量在赋值时解释器会根据值的类型创建对应的内存空间进行存储,并将变量指向这个地址空间即可,比如运行a=1时,解释器将变量指向整形值1的地址,当运行a=0.1时,解释器将变量指向浮点值0.1的地址。
说明:此处的例程测试环境为Ubuntu 16.04 LTS 32 位,不同的环境下测试结果可能会由于解释器的优化不同而有所不同。比如有网友发现解释器为两个相同浮点类型值的变量分配了不同的内存空间。
Python基础系列讲解—动态类型语言的特点的更多相关文章
- Python基础系列讲解——继承派生和组合的概念剖析
Python作为一门面向对象的语言,它的面向对象体系中主要存在这么两种关系,一个是“类”和“实例”的关系,另一个是“父类”和“子类”的关系. 所谓“类”是从一堆对象中以抽象的方式把相同的特征归类得到的 ...
- Python基础系列讲解——try_except异常处理机制
在Python编程中不可避免的会出现错误,在调试阶段出现语法之类的错误时,Pycharm会在Debug窗口提示错误,但是程序在运行时由于内部隐含的问题而引起错误,会导致程序终止执行.比如以下例程中,使 ...
- Python基础系列讲解——random模块随机数的生成
随机数参与的应用场景大家一定不会陌生,比如密码加盐时会在原密码上关联一串随机数,蒙特卡洛算法会通过随机数采样等等.Python内置的random模块提供了生成随机数的方法,使用这些方法时需要导入ran ...
- Python基础系列讲解——TCP协议的socket编程
前言 我们知道TCP协议(Transmission Control Protocol, 传输控制协议)是一种面向连接的传输层通信协议,它能提供高可靠性通信,像HTTP/HTTPS等网络服务都采用TCP ...
- Python基础系列讲解-自动控制windows桌面
原链接:https://zhuanlan.zhihu.com/p/73001806 在使用PC时与PC交互的主要途径是看屏幕显示.听声音,点击鼠标和敲键盘等等.在自动化办公的趋势下,繁琐的工作可以让程 ...
- Python基础系列讲解——时间模块详解大全之time模块
Python中提供处理时间日期相关的内置模块有time.datetime和calendar. time模块中大多数函数调用了所在平台C library 的同名函数,因此更依赖于操作系统层面,所以tim ...
- Python 语言特性:编译+解释、动态类型语言、动态语言
1. 解释性语言和编译性语言 1.1 定义 1.2 Python 属于编译型还是解释型? 1.3 收获 2. 动态类型语言 2.1 定义 2.2 比较 2. 动态语言(动态编程语言) 3.1 定义 3 ...
- python基础系列教程——Python3.x标准模块库目录
python基础系列教程——Python3.x标准模块库目录 文本 string:通用字符串操作 re:正则表达式操作 difflib:差异计算工具 textwrap:文本填充 unicodedata ...
- 【转】解析JDK 7的动态类型语言支持
http://www.infoq.com/cn/articles/jdk-dynamically-typed-language Java虚拟机的字节码指令集的数量自从Sun公司的第一款Java虚拟机问 ...
随机推荐
- 命令行编译执行java
命令行编译运行java程序 使用命令 javac进行编译 和 java进行执行. javac 后面跟着的是java文件的文件名,例如 HelloWorld.java. 该命令用于将 java 源文件编 ...
- for 循环使用 enumerate 以及yield生成器简单例子
>>>seq = ['one', 'two', 'three'] >>> for i, element in enumerate(seq): ... print i ...
- Putty等工具中解决SSH连接超时断开的问题
转自:http://www.putty.ws/putty-chaoshi 1 在 linux下的ssh命令:vim /etc/ssh/ssh_config 然后找到里面的ServerAliveInte ...
- overflow:hidden 影响inline-block元素周围元素下移
前言: 最近在切页中,我想实现左边一个类似下拉选框,且不允许输入,右边有一段垂直居中的文字描述的效果.我对文字用的是p标签.其实可以用个i/b/em等其他行内标签,同时也具有一定语义,做为强调提示,( ...
- javascript 深入理解 继承(转)
通过对继承的深入理解,更了解javascript.本人还不太写会博客,转自汤姆大叔,链接http://www.cnblogs.com/TomXu/archive/2012/01/05/2305453. ...
- Qt样式总结
说明 将Qt样式进行一下总结, 以后逐步更新 QPushbutton QPushbutton setStyleSheet("QPushButton{ border:1px solid #40 ...
- linux-2.6内核驱动学习——jz2440之按键
//以下是学习完韦东山老师视屏教程后所做学习记录中断方式取得按键值: #include <linux/module.h> #include <linux/kernel.h> ...
- Vivado中xilinx_BRAM IP核使用
Vivado2017.2 中BRAM版本为 Block Memory Generator Specific Features 8.3 BRAM IP核包括有5种类型: Single-port RA ...
- 20155339 《信息安全系统设计》第十周课下作业-IPC
20155339 <信息安全系统设计>第十周课下作业-IPC 共享内存 共享内存是在多个进程之间共享内存区域的一种进程间的通信方式,由IPC为进程创建的一个特殊地址范围,它将出现在该进程的 ...
- bzoj1043 [HAOI2008]下落的圆盘
Description 有n个圆盘从天而降,后面落下的可以盖住前面的.求最后形成的封闭区域的周长.看下面这副图, 所有的红色线条的总长度即为所求. Input 第一行为1个整数n,N<=1000 ...