python中可变对象与不可变对象

本文探讨了Python中的可变对象(如列表、字典和集合)与不可变对象(如整数、浮点数、字符串和元组)的概念。在Python中,可变对象在内容更改后地址不变,而不可变对象内容改变则会改变其地址。文章通过实例解释了函数参数传递中的引用传递,并分析了加不加return时对可变和不可变对象的影响,揭示了Python中对象赋值和复制的深层次理解。

1 基本概念

在python中一切皆对象,但对象有可变对象与不可变对象之分。

可变与不可变指的是其内容是否可变。

  • 可变对象

对象创建完之后内容可改变,但地址不会变

  • 不可变对象

对象创建之后内容不可改变,如果改变其地址也会变

参考https://www.runoob.com/note/46684

2 可变对象

可变对象有:列表,字典,集合等

  • 对于列表
l1 = [[1],1]
print(id(l1))
l1.append(2)
print(id(l1))
l1[0].append(2)
print(id(l1))

结果

2267960772104
2267960772104
2267960772104

id是对象的地址,是十进制的表示方式。对列表l1做了改变,但其地址并未变。

  • 对于字典、集合

# dict
d1 = {"a":1,"b":2}
print(d1, id(d1))
d1["c"] = 3
print(d1, id(d1))
d1["a"] = 0
print(d1, id(d1))

# set
s1 = {1,2}
print(s1, id(s1))
s1.add(3)
print(s1, id(s1))
s1.remove(2)
print(s1, id(s1))

# 结果
{'a': 1, 'b': 2} 2575808202440
{'a': 1, 'b': 2, 'c': 3} 2575808202440
{'a': 0, 'b': 2, 'c': 3} 2575808202440

{1, 2} 2575808614472
{1, 2, 3} 2575808614472
{1, 3} 2575808614472

同样内容变了,地址没有变

3 不可变对象

有int,float,字符串,tuple

# 不可变对象
i = 1
print(i, id(i))
i +=1
print(i, id(i))

#结果
1 1931280880
2 1931280912

变量i存的是对象的引用

4 为什么要有可变与不可变之分

自认为是为了函数的参数传递问题,python只允许使用引用传递

5 函数传参-引用传递

函数外部变量,函数内部调用了,其外部变量会不会变

  • 不加return
def change(a, b):
    # a是int,b是列表
    if not isinstance(a, int):
        print("a不是int类型")
        return -1
    if not isinstance(b, list):
        print("b不是list类型")
        return -1
    a +=1
    b.append(4)

i = 1
l1 = [1,2,3]
print(i, id(i))
print(l1, id(l1))


# 结果

1 1932067312
[1, 2, 3] 2370243772168

1 1932067312
[1, 2, 3, 4] 2370243772168

change()函数增加是对a,b的改变。

从结果可以看出

  • 不可变对象i,在函数内部改变,其内容和地址都不会变,实际上是函数内部的id对象改变了,只不过没有返回
  • 可变对象l1,在函数内部改变,其内容改变了,地址没有变

上面是在没有接收返回结果的条件下,也就是没有return a,b

加return

def change2(a, b):
    # a是int,b是列表
    if not isinstance(a, int):
        print("a不是int类型")
        return -1
    if not isinstance(b, list):
        print("b不是list类型")
        return -1
    a +=1
    b.append(4)
    return a, b

m = 0
lis = [0, 0]
result1, result2 = change2(m,lis)
print("之前:", m, id(m), lis, id(lis))
print("之后:", result1, id(result1), result2, id(result2))
print(id(lis))

# 结果
之前: 0 1932067280 [0, 0, 4] 1561835406856

之后: 1 1932067312 [0, 0, 4] 1561835406856
1561835406856

不可变对象,接受返回对象后,其值可地址都改变了,这比较符合不可变对象的定义:不可变对象内容改变,地址改变

对于可变对象

  • 用新的变量result2接受返回对象后,result2相对于原来的lis内容改变,地址不变
  • 原来的变量lis的内容改变,地址没变
  • 也符合可变对象的定义,内容改变,地址不变

那有个问题,新的变量result2和原来的变量lis地址和内容都一样,是同一个变量吗?改变其中一个变量的内容,另外一个会不会变?

验证:在原来的代码基础上增加

  • 只改变lis
# result2和lis,一个改变另外一个会不会变
print("before: lis={0}, result2={1}".format(lis, result2))
lis.append("只改变lis")
print("只改变lis:lis={0}, result2={1}".format(lis, result2))

#结果
before: lis=[0, 0, 4], result2=[0, 0, 4]

只改变lis:lis=[0, 0, 4, '只改变lis'], result2=[0, 0, 4, '只改变lis']

从结果来看,只改变lis,result2也跟着改变

  • 只改变result2

应该是两个都变

print("before: lis={0}, result2={1}".format(lis, result2))
result2.append("只改变result2")
print("只改变result2:lis={0}, result2={1}".format(lis, result2))

# 结果
before: lis=[0, 0, 4], result2=[0, 0, 4]

只改变result2:lis=[0, 0, 4, '只改变result2'], result2=[0, 0, 4, '只改变result2']

和预期一样,两个都改变

lis和result2都指向同一地址,内容都一样,类似与同一地址,不同标签

和列表的赋值操作差不多,即result2=lis

这要牵扯到可变对象的复制问题了

https://blog.youkuaiyun.com/u011630575/article/details/78599918

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值