Python中的变量、引用和作用域

时间:2021-09-27 06:07:25

Python中的变量、引用和作用域

可变对象 & 不可变对象

在python中,对象分为两种:可变对象和不可变对象。不可变对象包括int,float,long,str,tuple等,可变对象包括list,set,dict等。这里说的不可变指的是值的不可变。对于不可变类型的变量,如果要更改变量,则会创建一个新值,把变量绑定到新值上,而旧值没有被引用就等待垃圾回收。可变类型数据对对象操作的时候,不需要再在其他地方申请内存。

>>> a = 1
>>> id(a)
140320746581480
>>> id(1)
140320746581480
>>> a = 3
>>> id(3)
140320746581432
>>> id(a)
140320746581432
>>> b = 3
>>> id(b)
140320746581432

变量无类型,对象有类型

python中,类型是属于对象的,而不是变量,变量和对象是分离的,对象是内存中存储数据的实体,变量则是指向对象的指针。

函数值传递

def func_int(a):
a += 4

def func_list(a_list):
a_list[0] = 4

t = 0
func_int(t)
print t
# output: 0

t_list = [1, 2, 3]
func_list(t_list)
print t_list
# output: [4, 2, 3]

第一个例子传值,而第二个例子传递了引用,主要是因为可变对象和不可变对象的原因:对于可变对象,对象的操作不会重建对象;而对于不可变对象,每一次操作就重建对象。

在函数参数传递的过程中,python其实就是把参数里传入的变量对应的对象的引用依次赋值给对应的函数内部变量。

参照上面的例子来说明更容易理解,func_int中的局部变量”a”其实是全局变量”t”所指向对象的另一个引用,由于整数对象是不可变的,所以当func_int对变量”a”进行修改的时候,实际上是将局部变量”a”指向到了整数对象”1”。所以很明显,func_list修改的是一个可变的对象,局部变量”a_list”和全局变量”t_list”指向的还是同一个对象。

作用域

  • python能够改变变量作用域的代码段是def,class,lamda
  • if/elif/else, try/except/finally, for/while并不能设计变量作用域的更改,也就是说他们的代码块中的变量,在外部也是可以访问的。
  • 变量搜索路径是:本地变量->全局变量

例如,在C中:

#include<stdio.h>
int main() {
if(2 > 0) {
int i = 0;
}
printf("i = %d", i);
return 0;
}

if子句引入了局部变量i,其对外不可见。因此接下来在printf函数中对变量i的引用会引发错误。

但在python中却并非如此:

if True:
i = 0
print i

在这段代码中,if子句并没有引入一个局部变量,变量i仍旧是处在全局作用域中,因此,变量i对于接下来的print语句是可见的。

在python中,使用一个变量之前不必预先声明它,但是在真正使用它之前,它必须已经绑定到某个对象;而名字绑定将在当前作用域中引入新的变量,同时屏蔽外层作用域中的同名变量。

i = 0
def f():
i = 8
print i
f()
print i

输出结果就是8和0,从局部到全局的过程。