一、Python 变量及赋值
变量是什么?变量是指在程序运行过程中,值会发生变化的量。变量就是存储在内存中的值,这就意味着在创建变量时会在内存中开辟一个空间。基于变量的数据类型,Python 解释器会分配指定内存,并决定什么数据可以被存储在内存中。因此,变量可以指定不同的数据类型,这些变量可以存储整数,小数或字符。除了经常听到变量外,可能还会经常听到常量这个词,常量是指在程序运行过程中,值不会发生变化的量。
无论是变量还是常量,在创建时都会在内存中开辟一块空间,用于保存它的值。
1.1、变量定义
Python 中的变量不需要声明,变量的赋值操作既是变量声明和定义的过程,当我们定义一个变量时,Python 解释器会根据语法和操作数决定对象的类型。如果了解 C 语言的同学应该知道,C 语言中变量的定义需要提前此变量的类型后才可被赋值。每个变量在内存中创建,都包括变量的标识,名称和数据这些信息。每个变量在使用前都必须赋值,变量赋值以后该变量才会被创建,且才可以被使用。
变量在程序中就是用一个变量名表示了,变量名必须是大小写英文、数字和 _ 的组合,且不能用数字开头。另外不能使用 Python 关键字作为变量名。
1、普通变量赋值
>>> Var = 10 >>> type(Var) <class 'int'>
2、定义一个变量,变量名为”var”,赋值了一个整数,我们使用 type 方法查看此变量的类型,可以看出是一个整数类型。
>>> Var = 10.1 >>> type(Var) <class 'float'>
3、此时变量 Var 是一个浮点型。
>>> Var ="school" >>> type(Var) <class 'str'>
4、此时变量 var 是一个字符串。
>>> Var = True >>> type(Var) <class 'bool'>
5、此时变量 var 是一个布尔值。
在 Python 中,等号“=”是赋值语句,可以把任意数据类型赋值给变量,同一个变量可以反复赋值,而且可以是不同类型的变量,如上操作就是把一个变量进行了多次赋值。
这种变量本身类型不固定的语言称之为动态语言,与之对应的是静态语言。静态语言在定义变量时必须指定变量类型,如果赋值的时候类型不匹配就会报错;比喻 C 语言和 java 都是静态语言,赋值语句如下:
int var=10; #变量 var 是一个整数 var='school'; #变量 var 是一个字符串
和静态语言相比,动态语言更灵活,就是这个原因。另外请不要把赋值语句的等号等同于数学的等号。比如下面的代码:
>>> x = 10 >>> x = x + 2 >>> print(x) 12
如果从数学上理解 x = x + 2 那无论如何是不成立的,在程序中,赋值语句先计算右侧的表达式 x + 2,得到结果 12,再赋给变量 x。由于 x 之前的值是 10,重新赋值后,x 的值变成 12。
1.2、变量赋值过程
Python 中的变量赋值,不是真正意义上的修改内存的值,而是将变量名和在内存中的值做了一个绑定,称之为“引用”。
当我们创建一个变量时:
>>> a = 'school'
这时,Python 解释器干了两件事情:
-
在内存中创建了一个’school’
-
在内存中创建了一个名为 a 的变量并指向’school’
也可以把一个变量 a 赋值给另一个变量 b,这个操作实际上是把变量 b 指向变量 a 所指向的数据,例如下面的代码:
>>> a = 'school' >>> b = a >>> a = 'teacher' >>> print(a) school
引用的优缺点:
好处:节省内存空间,多个变量可以指向同一个地址。坏处:如果修改变量的变量值在内存中不存在,需要重新申请内存,绑定变量名和地址,降低了执行效率。
Python 变量赋值和修改值得实际过程:
>>> x = 2 >>> y = 3 >>> id(x) 32771152 >>> id(y) 32771128
当你创建一个变量 x,值等于 2 时;Python 解释器会先找内存中有没有 2 的值,如果有直接做绑定,然后 2 这个值得引用计数加 1 即可。如果没有那么 Python 解释器就需要开辟一段内存空间,创建一个 2 的值,我们使用 id(x)可以看出变量 x 当前引用的内存地址。同样变量 y 也是这样的操作。
此时,我们如果修改变量 x = 3,那么 Python 解释器就会把变量 x 的与内存地址”32771128″做绑定,然后把 3 的引用加 1,如下操作:
>>> x = 3 >>> id(x) 32771128
那么此时,内存中的整数值“2”就没有被引用了,当 Python 解释器检查到“2”的引用为 0 时就会启动内存回收机制把此内存空间给释放掉了。
二、Python 解释器内部机制
Python 引用计数机制
要保持追踪内存中的对象,python 使用了引用计数这一简单计数。也就是说 python 内部记录着所有使用中的对象各有多少引用。一个内部跟踪变量也称为引用计数器。每个对象各有多少个引用简称引用计数;当对象被创建时,就创建了一个引用计数,当这个对象不再需要时,也就是说这个对象的引用计数变为 0 时它会被当垃圾回收。
Python 垃圾回收机制
在 python 中不再使用的内存会被一种称为垃圾收集的机制释放。像上面说的,虽然解释器跟踪对象的引用计数,但垃圾收集器负责释放内存。垃圾收集器是一块独立代码,它用来寻找引用计数为 0 的对象。它也负责检查哪些虽然应用计数大于 0 但也应该被销毁的对象。特定情形会导致循环引用。
三、变量赋值的方法
1)普通变量赋值
>>> x = 1 >>> y = 'school'
2)增量赋值
>>> x = 2 >>> x += 2 >>> x
4
3)多重赋值
>>> y = x = z = 1 >>> y 1 >>> x 1 >>> z 1
4)多元赋值
>>> x,y = 1,'str' >>> x 1 >>> y 'str'
>>> x = 10 >>> y = 20 >>> x,y = y,x >>> x 20 >>> y 10
5)分解赋值元祖和列表分解赋值时当赋值符号(*)的左侧为元祖或列表时、Python 会按照位置把右边的对象和左边的目标自左而右逐一进行配对;个数不同时会触发异常,此时可以切片的方式进行.
>>> one = (1,2,3) >>> x,y,z = one >>> print x 1
四、变量的作用域
作用域简单说就是一个变量的命名空间。代码中变量被赋值的位置,就决定了哪些范围的对象可以访问这个变量,这个范围就是命名空间。Python 赋值时生成了变量名,当然作用域也包括在内。
Python 变量作用域遵循 LEGB 原则:
-
L (Local) 局部作用域
-
E (Enclosing) 闭包函数外的函数中
-
G (Global) 全局作用域
-
B (Built-in) 内建作用域
以 L –> E –> G –>B 的规则查找,即:在局部找不到,便会去局部外的局部找(例如闭包),再找不到就会去全局找,再者去内建中找。
在def/class/lambda
内定义的变量名,只能被函数内部引用,不能在函数外引用这个变量名,这个变量的作用域就是局部的,也叫它为局部变量。在def/class/lambda
外,一段代码最始开所赋值的变量,它可以被多个函数引用,这就是全局变量。局部作用域会覆盖全局作用域,但不会影响全局作用域。
如果函数内的变量名与函数外的变量名相同,也不会发生冲突。好比下面这种情况:
x = 100 def func(): x = 55
-
x = 100 这个赋值语句所创建的变量 X,作用域为全局变量。
-
x = 55 这个赋值语句所创建的变量 X,它的作用域则为局部变量,只能在函数 func()内使用。
尽管这两个变量名是相同的,但它的作用域为它们做了区分。作用域在某种程度上也可以起到防止程序中变量名冲突的作用。每次对函数的调用都会创建一个新的本地作用域,赋值的变量除非使用 global 申明为全局变量否则均为本地变量。