Loading

Python - 变量与内存管理

变量

我们通过一个名字,指向一个人,或者指向一个具体的事物。这在Python中是同样适用。Python中,这个名字称为变量,而指向的对象为一串字符串,一个具体的数值等等。变量也是可变状态的、对内存地址一种抽象。

变量赋值

变量赋值是指将一个数字或者字符串等具体的数值数据赋值给一个变量,在后面的编程中我们可以通过这个变量来指向所要引用的数据对象。比如:

>>> v = 100  
>>> v  
100  
>>> v+20  
120  

变量用 =来给数据赋值,等号的左边是变量名,右边则是要存储在变量中的值。上例中,我们称第1行为变量定义,第2行为引用。每一个变量在使用的时候,都要经过先定义才能引用。
你可能会问,直接使用100不就好了么,为什么还要有变量呢?因为变量在程序的执行过程中,能始终的指向这个值,无论这个值发生怎么样的变化,除非我们手动的解除指向关系。比如,你在打游戏的时候,我们对人物的血量这个变量进行跟踪。开始出门,人物的血量是满的,但是当人物受伤血量不断变动的时候,我们可以通过这个变量修改此时的状态而不是去修改程序,而当我们检测到这个变量为空时,我们可以执行其他操作,这就是变量的好处。
另外,Python还支持另一种赋值方式:链式赋值

>>> a = b = c = 1  
>>> a  
1  
>>> b  
1  
>>> c  
1  

除此之外,也可以为多个对象指定多个变量:序列赋值。

>>> a, b, c = 1, 12, "oldboy"  
>>> a  
1  
>>> b  
12  
>>> c  
'oldboy'  

变量赋值操作虽然简单,但也有自己的规则,我们来学习变量的命名规范:

  • 第一个字符必须是字母(大写或小写)或者一个下划线(_
  • 变量的其他部分可以是字母(大写或小写)、下划线(_)、数字(0-9)组成
  • 变量是对大小写敏感的。如,oldboyoldBoy不是一个变量
  • 变量命名时注意避开关键字和内置的函数名,以免发生冲突
  • 变量的第一个字母不能是数字
  • 变量命名最好做到见名知意,比如:
name = "zhangkai"
age = 18

而不是这种:

mingzi = "zhangkai"
nianling = 18
a = "male"
b = "不详"

你能一眼看出ab这两个变量代指的是什么意思吗?
我们还应该避免:

  • 单字符名称
  • 包/模块名中的连接符避免用中横线-
  • 避免双下划线开头并结尾的名称,因为这是Python保留的,比如__init__

既然上文提到我们在变量命名时要避开关键字,那么就先通过一个模块,来看看那些是Python的关键字:

>>> import keyword  
>>> keyword.kwlist 			# 所有关键字  
['False', 'None', 'True', 'and', 'as', 'assert', 'break', 'class', 'continue', 'def', 'del', 'elif', 'else', 'except', 'finally', 'for', 'from', 'global', 'if', 'import', 'in', 'is', 'lambda', 'nonlocal', 'not', 'or', 'pass', 'raise', 'return', 'try', 'while', 'with', 'yield'] 
>>> keyword.iskeyword('is')    # 查看某个变量是否为关键字  
True  
>>> help('keywords')            # help方法查看关键字  
Here is a list of the Python keywords.  Enter any keyword to get more help.  
False               def                 if                  raise  
None                del                 import              return  
True                elif                in                  try  
and                 else                is                  while  
as                  except              lambda              with  
assert              finally             nonlocal            yield  
break               for                 not  
class               from                or  
continue            global              pass  

小结:
Python属于强类型的语言。如果定义了一个字符串类型的a。如果不经过强制转换,那么它就永远是字符串类型的了,程序根本不可能把它当做整形来处理。所以,Python也是类型安全的语言。
说到变量,那就不得不说一下常量。一般的来说,变量,就是代指不断变化的量,而常量指(Python在语法上并没有定义常量,尽管PEP8规范定义了常量的命名规范为全部大写字母和下划线组成),基本上定义了之后不怎么变化的变量。比如我们保存一段信息:

IP = "127.0.0.1"

内存管理

在刚才的变量赋值中,我们学习了关于变量的知识,即通过一个变量来保存数据,以便于调用。那么,赋值在内部是怎么实现的呢?这就是我们接下来要说的内存存储了。

>>> x = 10  
>>> y = x  
>>> y  
>>> 10  
>>> y = 20  
>>> y  
20  
>>> x  
10  
>>> y = 30  
>>> y  
30  
>>> x  
10  

我们通过上例来研究一下变量及值在内存中的存储过程:
第1行:解释器执行代码x=10时,会开辟一块内存空间,然后将生成的数据对象10存放到该内存空间中,该内存空间有自己的内存地址,可以理解成为房间的门牌号。变量x也有自己的内存空间,存储的是赋值的数据对象的内存地址,此时称变量x是对该内存空间的数据10的引用。使用变量x时,就会通过其保存的内存地址找到该地址下的值,过程如图所示。

第2行:解释器执行代码y=x时,会将x保存的内存地址存储到变量y自己的内存空间,此时,变量y也是对0010空间下的数据10的引用,所以打印y的值也会找到0010下的10,如图所示。

为了验证这一点,可以使用Python另一个内置函数:id(obj),它的功能是用于获取对象obj的内存地址。

>>> id(x)  
4297546848  
>>> id(y)  
4297546848  

第5行:解释器执行代码y=20时,会新生成一个整数对象存放到内存地址为0011的内存空间中,此时y的内存空间内不在存储0100,而是存储0011 。所以,打印y的值成为了20,而x则依然是10,如图所示。

第10行:解释器执行代码y=30时,首先解除与20的绑定关系,然后与30建立绑定关系,如图所示。

那么,问题来了,整型数据对象20去哪了?这就说到垃圾回收机制:Python解释器会每隔很短的时间内扫描一下内存中的数据,对于那些没有变量引用的,直接当作垃圾清除掉。此例中,当变量y存储的内存地址由0011换成0111后,整个内存不再有变量引用数据20,所以20就被解释器的垃圾回收机制从内存中清除了。

而如果要将10清除掉呢?因为10由变量x作为引用,所以清空x的内存空间,不再引用10即可,具体语法由del实现:

del x  

当然,此时再打印x,直接抛错,因为x现在没有指向任何变量,所以就抛出一个变量x未定义的错误。

>>> x  
Traceback (most recent call last):  
  File "<stdin>", line 1, in <module>  
NameError: name 'x' is not defined  

提示:del 也可以同时删除多个对象。

>>> x, y = 1, 2  
>>> x, y  
(1, 2)  
>>> del x, y  
>>> x  
Traceback (most recent call last):  
  File "<stdin>", line 1, in <module>  
NameError: name 'x' is not defined  
>>> y  
Traceback (most recent call last):  
  File "<stdin>", line 1, in <module>  
NameError: name 'y' is not defined  

欢迎斧正,that' all
posted @ 2019-03-15 09:32  听雨危楼  阅读(451)  评论(0编辑  收藏  举报