python的数据类型分为可变与不可变类型,在六大数据类型中,数字,字符串,元组为不可变类型,列表,字典,集合为可变类型
python数据的引用其实是引用变量在内存的地址空间,当数据被更改时,不可变类型会重新开辟新的地址空间再对变量赋值,而可变类型则就会在原地址空间进行修改
看下面的例子:
a="abc"
b="abc"
print(id(a),id(b))
输出为:
1539522378640 1539522378640
a="cba"
print(a,b)
print(id(a),id(b))
输出结果:
cba abc
1539572784688 1539522378640
可以看到不可变类型在改变值后,地址空间也改变了
而不可变的类型在重新赋值时会发生下列的情况
a=["abc"]
b=a
print(a,b)
print(id(a),id(b))
结果为
[‘abc’], [‘abc’]
1539571459528 1539571459528
a.append("def")
print(a,b)
print(id(a),id(b))
结果打印为:
[‘abc’, ‘ddd’],[‘abc’, ‘ddd’]
1539571495112 1539571495112
可以看到b的值也改变了,因为在对a更改的时候,a的地址空间并没有变,而b的地址空间还是指向原来的位置的,所以b的值也跟着改变了
在函数作用域的坑:
我们知道函数作用域有全局变量与局部变量
全局变量能够被所有函数共享,但是能不能被函数更改呢,看一下下面的例子:
def fn(n):
n += 1
num = 1
fn(num)
print(num)
输出结果:
1
函数把num的值改了,但是开辟了新的地址空间,并没有影响到全局num的地址值,所以全局num的值没有改变
再看下面的例子:
def fn(list_test):
list_test.append("two")
list_a = ["one"]
fn(list_a)
print(list_a)
输出结果:
[‘one’, ‘two’]
这里看到全局变量list_a的值被更改了,因为函数fn在更改list的值时,只是在原来的地址空间上改,所以全局变量list_a还是指向原来的地址空间,即被更改后的值,这点需要特别注意
再看另外一个列子:
class Person:
name = ["renyi"]
age = 24
a = Person()
a.name[0] = "mayun"
a.age = 50
# 这时候我们再实例化一个对象b
b = Person()
print(b.name, b.age)
想一想会输出什么?