python变量生命周期
Ⅰ 为什么说python采用的是基于值的内存管理模式
先从较浅的层面来说,Python的内存管理机制可以从三个方面来讲
(1)垃圾回收
(2)引用计数
(3)内存池机制
一、垃圾回收:
python不像C++,Java等语言一样,他们可以不用事先声明变量类型而直接对变量进行赋值。对Python语言来讲,对象的类型和内存都是
在运行时确定的。这也是为什么我们称Python语言为动态类型的原因(这里我们把动态类型可以简单的归结为对变量内存地址的分配是在运行时自动判断变量
类型并对变量进行赋值)。
二、引用计数:
Python采用了类似Windows内核对象一样的方式来对内存进行管理。每一个对象,都维护这一个对指向该对对象的引用的计数。如图所示(图片来自Python核心编程)
x = 3.14
y = x
我们首先创建了一个对象3.14, 然后将这个浮点数对象的引用赋值给x,因为x是第一个引用,因此,这个浮点数对象的引用计数为1. 语句y =
x创建了一个指向同一个对象的引用别名y,我们发现,并没有为Y创建一个新的对象,而是将Y也指向了x指向的浮点数对象,使其引用计数为2.
我们可以很容易就证明上述的观点:
变量a 和 变量b的id一致(我们可以将id值想象为C中变量的指针).
我们援引另一个网址的图片来说明问题:对于C语言来讲,我们创建一个变量A时就会为为该变量申请一个内存空间,并将变量值
放入该空间中,当将该变量赋给另一变量B时会为B申请一个新的内存空间,并将变量值放入到B的内存空间中,这也是为什么A和B的指针不一致的原因。如图:
而Python的情况却不一样,实际上,Python的处理方式和Javascript有点类似,如图所示,变量更像是附在对象上的标签(和引用的
定义类似)。当变量被绑定在一个对象上的时候,该变量的引用计数就是1,(还有另外一些情况也会导致变量引用计数的增加),系统会自动维护这些标签,并定
时扫描,当某标签的引用计数变为0的时候,该对就会被回收。
三、内存池机制
Python的内存机制以金字塔行,-1,-2层主要有操作系统进行操作,
第0层是C中的malloc,free等内存分配和释放函数进行操作;
第1层和第2层是内存池,有Python的接口函数PyMem_Malloc函数实现,当对象小于256K时有该层直接分配内存;
第3层是最上层,也就是我们对Python对象的直接操作;
在 C 中如果频繁的调用 malloc 与 free 时,是会产生性能问题的.再加上频繁的分配与释放小块的内存会产生内存碎片. Python 在这里主要干的工作有:
如果请求分配的内存在1~256字节之间就使用自己的内存管理系统,否则直接使用 malloc.
这里还是会调用 malloc 分配内存,但每次会分配一块大小为256k的大块内存.
经由内存池登记的内存到最后还是会回收到内存池,并不会调用 C 的 free
释放掉.以便下次使用.对于简单的Python对象,例如数值、字符串,元组(tuple不允许被更改)采用的是复制的方式(深拷贝?),也就是说当将另
一个变量B赋值给变量A时,虽然A和B的内存空间仍然相同,但当A的值发生变化时,会重新给A分配空间,A和B的地址变得不再相同;
而对于像字典(dict),列表(List)等,改变一个就会引起另一个的改变,也称之为浅拷贝:
附录:
引用计数增加
1.对象被创建:x=4
2.另外的别人被创建:y=x
3.被作为参数传递给函数:foo(x)
4.作为容器对象的一个元素:a=[1,x,’33’]
引用计数减少
1.一个本地引用离开了它的作用域。比如上面的foo(x)函数结束时,x指向的对象引用减1。
2.对象的别名被显式的销毁:del x ;或者del y
3.对象的一个别名被赋值给其他对象:x=789
4.对象从一个窗口对象中移除:myList.remove(x)
5.窗口对象本身被销毁:del myList,或者窗口对象本身离开了作用域。
垃圾回收
1、当内存中有不再使用的部分时,垃圾收集器就会把他们清理掉。它会去检查那些引用计数为0的对象,然后清除其在内存的空间。当然除了引用计数为0的会被清除,还有一种情况也会被垃圾收集器清掉:当两个对象相互引用时,他们本身其他的引用已经为0了。
2、垃圾回收机制还有一个循环垃圾回收器, 确保释放循环引用对象(a引用b, b引用a, 导致其引用计数永远不为0)。
Ⅱ 软件测试中,python中的 ==和 is 之间的区别
在Python中一切都是对象。
Python中对象包含的三个基本要素,分别是:id(身份标识)、type(数据类型)和value(值)。对象之间比较是否相等可以用==,也可以用is。
is和==都是对对象进行比较判断作用的,但对对象比较判断的内容并不相同。下面来看看具体区别在哪?
is比较的是两个对象的id值是否相等,也就是比较两个对象是否为同一个实例对象,是否指向同一个内存地址。
==比较的是两个对象的内容是否相等,默认会调用对象的__eq__()方法。
以下代码在Python3.5下测试通过。
==比较操作符和is同一性运算符区别
==是python标准操作符中的比较操作符,用来比较判断两个对象的value(值)是否相等。
代码1:
>>> a = [1, 2, 3]
>>> b = a
>>> b is a
True
>>> b == a
True
>>> b = a[:]
>>> b is a
False
>>> b == a
True
解释一下为什么?is也被叫做同一性运算符,也就是id是否相同。看下面代码, a和b变量的id不同, 所以b==a是True, b is a 是False.
代码2:
>>> id(a)
4364243328
>>>
>>> id(b)
4364202696
哪些情况下is和==结果是完全相同的?
代码3:
>>> a = 256
>>> b = 256
>>> a is b
True
>>> a == b
True
>>>
>>> a = 1000
>>> b = 10**3
>>> a == b
True
>>> a is b
False
>>>
结论:数字类型不完全相同。
为什么256时相同, 而1000时不同?
因为出于对性能的考虑,Python内部做了很多的优化工作,对于整数对象,Python把一些频繁使用的整数对象缓存起来,保存到一个叫small_ints的链表中,在Python的整个生命周期内,任何需要引用这些整数对象的地方,都不再重新创建新的对象,而是直接引用缓存中的对象。Python把这些可能频繁使用的整数对象规定在范围[-5, 256]之间的小对象放在small_ints中,但凡是需要用些小整数时,就从这里面取,不再去临时创建新的对象。
代码4:
>>> c = 'pythontab.com'
>>> d = 'pythontab.com'
>>> c is d
False
>>> c == d
True
>>> c = 'pythontabcom'
>>> d = 'pythontabcom'
>>> c is c
True
>>> c == d
True
结论:字符串类型不完全相同。这个和解释器实现有关。
代码5:
>>> a = (1,2,3) #a和b为元组类型
>>> b = (1,2,3)
>>> a is b
False
>>> a = [1,2,3] #a和b为list类型
>>> b = [1,2,3]
>>> a is b
False
>>> a = {'python':100,'com':1} #a和b为dict类型
>>> b = {'python':100,'com':1}
>>> a is b
False
>>> a = set([1,2,3])#a和b为set类型
>>> b = set([1,2,3])
>>> a is b
False
结论
当变量是数字、字符串、元组,列表,字典时,is和==都不相同, 不能互换使用!当比较值时,要使用==,比较是否是同一个内存地址时应该使用is。当然,开发中比较值的情况比较多。
Ⅲ Python其实很简单 第五章 基本数据类型
编程的目的就是为了处理信息,信息则是由各种不同类型的数据表示的,对数据的进一步处理也会使信息更加丰富和有效。
5.1变量
前面已经提到过“变量”这属语,下面再进一步解释一下。
在程序运行时,必须把数据导入计算机的存储单元中,但存储单元的命名是用二进制数表示的,晦涩难懂。为了方便起见,可以给存储单元起上一个通俗易懂的名字,即 变量名 。
变量的生命周期和程序的运行周期是相同的,一个程序运行解释,所占用的存储空间也就随之释放,用变量名表示的数据所占用的这个存储单元也就空闲了。
变量名的命名规则:
由字母、数字、下划线构成,必须由字母开头。
不能包含-、*、?、#、、;、/、、@、%、$、空格等特殊字符。
最好使用有含义的英文单词或汉语拼音。
最好采用小写字母。
不能使用保留字(已被Python语言系统本身赋予特定意义的单词)。Python的保留字如下表所示。
Python保留字列表
Python是区分大小写的,虽然可以将一个英文单词通过字母大小写不同而作为不同变量的变量名,但从程序可读性的角度看,的确不可取。
Python是一种动态类型的语言,变量的类型由变量的值决定。换而言之,给变量赋何种类型的值,变量就是该值的类型。给变量赋值可以通过赋值号(=)来实现。如:
>>> myvar=100
>>> type(myvar)
>>> myvar='tom'
>>> type(myvar)
在这个例子中,变量myvar首先赋值为100,显而易见,100是个整数,通过type()这个函数检测,变量myvar的类型为整数类型(int);接下来变量myvar赋值为‘tom’,通过type()这个函数检测,变量myvar的类型改变为字符串类型(str)。
不仅可以给一个变量赋值为常量,也可以赋值为另一个变量。如:
>>> a=100
>>> b=a
>>> b
100
在这个例子中,“b=a”的实际意义是,变量b和变量a指向同一个存储单元,既然是同一个存储单元,变量b和变量a本质上就是完全相同的,这就好比一个人除了本名之外,还有其他的名字,如笔名、昵称、乳名等等,虽然本质一样,但是可以在不同场合使用。
5.2关于Python的常量问题
在大多数语言中都有常量这个概念,但是Python却没有。其实仔细想想也好像没有设置常量的必要,只要一个变量的值不发生变化,即不给变量重新赋值,它的值当然不会变化,它便是个常量。
5.3基本数据类型
5.3.1整数型和浮点数
整数型(integer),可以是正整数、负整数和0,可以是十进制、八进制、二进制等。
浮点数(float),由整数部分和小数部分组成,主要用于处理包括小数的数。浮点数也可以用科学计数法表示。
5.3.2 字符串类型
字符串类型是由一系列的字母或者其他符号组成的数据序列,通常用单引号、双引号或三引号括起来。
用单引号和双引号括起来的字符串只能放在同一行,用三引号括起来的字符串可以分布在连续多行上。如:
name='我的名字叫王小明'
old="今年6岁"
introce='''我想说: 我是中国娃
爱讲普通话
要学习写标准的汉字'''
print(name)
print(old)
print(introce)
运行结果为:我的名字叫王小明
今年6岁
我想说: 我是中国娃
爱讲普通话
要学习写标准的汉字
不管是哪一种引号形式,括起来的部分是一个整体,包括空格和换行符都属于字符串的一部分。
为了保证特殊的输出效果,Python中的字符串支持转义字符,可使用反斜杠“”对一些特殊字符进行转义。常用的转义字符如下:
续行符
换行符
空
水平制表符
” 双引号
’ 单引号
一个反斜杠
f 换页
其中,续行符(“”)用于当一个字符串在一行写不下时用续行符进行连接,但通常更多的采用小括号“()”即可。
如:
第一种方法采用续行符(“”):
>>> str="A thousand wishes, a thousand plans and
a thousand resolutions are better than one action!"
>>> print(str)
A thousand wishes, a thousand plans and a thousand resolutions are better than one action!
第二种方法采用小括号():
>>> str=("A thousand wishes, a thousand plans and "
"a thousand resolutions are better than one action!")
>>> print(str)
A thousand wishes, a thousand plans and a thousand resolutions are better than one action!
下面举例说明换行符(“ ”)的用法:
>>> str=" 登鹳雀楼 白日依山尽, 黄河入海流。 欲穷千里目, 更上一层楼。 "
>>> print(str)
登鹳雀楼
白日依山尽,
黄河入海流。
欲穷千里目,
更上一层楼。
下面举例说明使用转义字符输出双引号(“)的方法:
>>> str="王之涣的诗《登鹳雀楼》中这样写道:" 白日依山尽,黄河入海流。欲穷千里目,更上一层楼。""
>>> print(str)
王之涣的诗《登鹳雀楼》中这样写道:" 白日依山尽,黄河入海流。欲穷千里目,更上一层楼。"
>>>
5.3.3布尔类型
布尔类型用来表示逻辑值,所谓逻辑判断的结果,不外乎“真”或“假”两种情况。在Python中“真”用True表示,“假”用False表示。如果布尔类型的变量参与算数运算,则True被当作1,False被当作0。
如:
>>> result=True
>>> print(result)
True
>>> print(result+1)
2
>>> result=False
>>> print(result)
False
>>> print(result+1)
1
5.3.4类型强制转换
Python是一种弱数据类型语言,可以通过给变量重新赋值的方法改变数据类型。但有时为了强制改变数据类型,就要使用类型转换函数来改变。
譬如,为了从键盘读入成绩的数据,可以用float()函数将input()语句读入的字符串转换为浮点数,再赋值给变量score。
>>> score=input("请输入您的成绩:")
请输入您的成绩:96.5 (从键盘输入96.5)
为了计算成绩比及格线高了多少分,使用下面的命令,发现出现了错误提示如下:
>>> score-60
Traceback (most recent call last):
File " ", line 1, in
score-60
TypeError: unsupported operand type(s) for -: 'str' and 'int'
这是属于类型错误,原因是从键盘读入的成绩值(96.5)并非数值类型,不能参与算数运算。用type()函数可以进一步查询变量score的数据类型。
>>> type(score)
使用float()函数进行强制转换后,就可以解决上述问题:
>>> score=float(input("请输入您的成绩:"))
请输入您的成绩:96.5
>>> score=float(score)
>>> type(score)
>>> score-60
36.5
下表列举了一些常用的类型转换函数: