要点:Python为动态型语言,对象和引用分离,属于传址调用;
Python的数据分为可变对象和不可变对象;
以上两者共同决定变量引用中的赋值变化
1. 动态语言的对象和引用分离
Python属于动态语言,引用和对象分离(动态类型的核心),在内存中,引用和对象将分别创建,同时将变量指向实体对象
a = 198 # 在内存中分别创建198的int对象和名称为a的变量;并将变量a指向198
b = a # 在内存中创建名为b的变量,并将b指向a所引用的对象198
d = [1,2,3] # 过程同上
e = d
2. 可变和不可变对象说明
可变对象:通过引用变量可以改变自身的对象类型。
a. 可以有多个相同对象;
b. 赋值语句会创造新的对象;
c. 列表(list)和字典(dictionary)属于可变对象
不可变对象:不能改变对象本身,只能改变引用指向的对象类型。
a. 每个不可变对象在内存中只存有一份(Python会缓存);
b. 赋值语句对于已经存在的不可变对象,只是增加新的指向
c. 数字(int、float)、字符串(string)和元组(tuple)属于不可变对象
自我理解:
变量:“咱改变一下,来点刺激的吧!!!“
可变对象:“哥,听你的,你想咋变,我就咋变“
不可变对象:“切,姐还嫌弃你了呢,想变找别人去,姐不伺候了,我走“
a = a + 1 # 不可变对象-->>创建199的对象,a重新指向199,b还是指向198
d[0] = d[0] + 1 # 可变对象-->>[1,2,3]将变为[2,2,3],所以e也会跟随变化
3. 函数演示内部变化
主要用到id()获取对象的内存地址
a = 111111111
b = a
c = 111111111
d = [1,3,5]
e = d
f = [1,3,5]
print("*********************")
print("1. 赋值的不同")
print(" 1.1 不可变对象")
print(" a = %s;id(a) = %s"%(a,id(a)))
print(" b = %s;id(b) = %s"%(b,id(b)))
print(" c = %s;id(c) = %s"%(c,id(c)))
print(" 1.2 可变对象")
print(" d = %s;id(d) = %s"%(d,id(d)))
print(" e = %s;id(e) = %s"%(e,id(e)))
print(" f = %s;id(f) = %s"%(f,id(f)))
a = a + 1
d[0] = d[0] + 1
print("2. 运算的不同")
print(" 2.1 不可变对象")
print(" a = %s;id(a) = %s"%(a,id(a)))
print(" b = %s;id(b) = %s"%(b,id(b)))
print(" c = %s;id(c) = %s"%(c,id(c)))
print(" 2.2 可变对象")
print(" d = %s;id(d) = %s"%(d,id(d)))
print(" e = %s;id(e) = %s"%(e,id(e)))
print(" f = %s;id(f) = %s"%(f,id(f)))
# 结果如下:
# *********************
# 1. 赋值的不同
# 1.1 不可变对象
# a = 111111111;id(a) = 6153072
# b = 111111111;id(b) = 6153072
# c = 111111111;id(c) = 6153072 # 新的赋值语句仍然指向原来的内存地址
# 1.2 可变对象
# d = [1, 3, 5];id(d) = 6876176
# e = [1, 3, 5];id(e) = 6876176
# f = [1, 3, 5];id(f) = 6876016 # 新的赋值语句创建了新的对象
# 2. 运算的不同
# 2.1 不可变对象
# a = 111111112;id(a) = 5592536 # 运算后,由111111111-->111111112,所以a的引用发生变化
# b = 111111111;id(b) = 6153072 # 变化后,b的取值没有变化,仍然引用111111111
# c = 111111111;id(c) = 6153072
# 2.2 可变对象
# d = [2, 3, 5];id(d) = 6876176 # 由[1,3,5]-->[2,3,5],但是内存地址没有发生变化
# e = [2, 3, 5];id(e) = 6876176 # 由于引用的内存地址上的数据变化,导致e也变为[2,3,5]
# f = [1, 3, 5];id(f) = 6876016
4. 参数调用的变化
def bukebian(x):
x = 100
print(" 函数值:x = %s;id(x) = %s"%(x,id(x)))
def kebian(y):
y[0]=100
print(" 函数值:y = %s;id(y) = %s"%(y,id(y)))
m = 1
n = [1,2,3,4]
print("1. 不可变对象")
print(" 变化前:m = %s ;id(m) = %s"%(m,id(m)))
bukebian(m) # 不可变对象函数中引用
print(" 变化后:m = %s ;id(m) = %s"%(m,id(m)))
print("2. 可变对象")
print(" 变化前:n = %s ;id(n) = %s"%(n,id(n)))
kebian(n) # 可变对象函数中引用
print(" 变化后:n = %s;id(n) = %s"%(n,id(n)))
# 变化结果如下:
#1. 不可变对象
# 变化前:m = 1 ;id(m) = 1420576400
# 函数值:x = 100;id(x) = 1420577984 # 参数调用m,其实是x引用1;x重新赋值为100,其实是x重新引用100
# 变化后:m = 1 ;id(m) = 1420576400 # m因为仍然指向1,所以没有发生变化
#2. 可变对象
# 变化前:n = [1, 2, 3, 4] ;id(n) = 6417424
# 函数值:y = [100, 2, 3, 4];id(y) = 6417424 # 调用[1,2,3,4]后,内存地址不变,但可变对象的值发生变化
# 变化后:n = [100, 2, 3, 4];id(n) = 6417424 # 引用的内存地址虽然没变,但内存地址存储的数据发生变化
总结:
变量引用不可变对象,只要是不重新赋值,引用的数据不会发生变化;
变量引用可变对象,其数据随着引用对象的变化而变化