Python的mutable值碎碎念

本文深入探讨了Python中可变类型如list、set、dict等在函数默认参数中的行为,解释了为何多次调用函数时会出现累积效果。此外,文章详细分析了浅拷贝与深拷贝的区别及应用场景,通过具体示例说明了不同数据类型的拷贝行为。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

如下案例:

>>> def test(a, b=[]):
...     b.append(a)
...     return b

>>> test(1)
[1]
>>> test(2)
[1, 2]
>>> test(3)
[1, 2, 3]

 

是由于对于python的可变类型list,set,dict等,它的关键字变量默认值是在函数定义的时候存在func_defaults里的,又因为可变类型是传引用,因此每一次调用都是变化的。

 

[另一方面,在嵌套函数中,python2的内层函数无法获取外层函数不可变变量,但可以访问可变变量,因此通常这样写

def test():

    a = [1]

    def t():

        print a[0]

    t()

把变量放在一个mutable里]X

这里有一个严重失误,像这样的闭包,python内存函数是可以访问外层的变量的,但对immutable变量不允许修改,外面有个a=1,里面可以print a,可以a=2,但不允许a += 2,之前的“无法获取”是错误的,谨记!!!

——————————————————————————————————————————————

说到mutable,一个值得探讨的问题就是copy和deepcopy。通常来说一个浅拷贝只拷贝可变参数的引用,当原数据发生修改时拷贝数据也会修改,考虑如下case:

>>> a = [1,2,[12]]
>>> b = a
>>> a = [2,3,[23]]
>>> a
[2, 3, [23]]
>>> b
[1, 2, [12]]

嘿?说好的同时修改呢?

实际上是因为a进行了一个赋值操作而非对象内的数据修改,因此指向了另外一片内存。浅拷贝的case如下:

>>> a = [1,2,[12]]
>>> b = a
>>> a[1] = 3
>>> a[2].append(3)
>>> b
[1, 3, [12, 3]]
>>>

对于序列来说,会发生浅拷贝的情况有切片,工厂函数list()和copy模块等。

深拷贝顾名思义是整个复制重开内存,这里不再赘述,不过有一点,python对于不可变变量,深拷也是直接拷引用的,反正不可变,节省空间~case如下:

>>> c = 1
>>> d = deepcopy(c)
>>> id(c),id(d)
(140569092332408, 140569092332408)

要特别注意元组类型,考虑如下case:

>>> a = (1,2)
>>> b = deepcopy(a)
>>> id(a),id(b)
(4482226008, 4482226008)
>>> a = (1,[12])
>>> b = deepcopy(a)
>>> id(a),id(b),id(a[0]),id(b[0]),id(a[1]),id(b[1])
(4482223208, 4482225792, 140569092332408, 140569092332408, 4482452008, 4482450280)

 

当元组数据均为immutable时,深拷是拷引用

当数据中有mutable时,深拷回开辟新内存,其中,immutable的变量指向同一处,mutable的指向不同处

另外,当元组中有可变数据进行浅拷时,可变数据修改也会同时发生。

————————————————————————————————————————————

immutable数据是可以自定义的,只要重写继承的object的__setattr__和__delattr__

 

  1. class Immutable(object):  
  2.     def __setattr__(self, *args):  
  3.         raise TypeError("can't modify the value of immutable instance")  
  4.   
  5.     __delattr__ = __setattr__  
  6.   
  7.     def __init__(self, value):  
  8.          super(Immutable, self).__setattr__("value", value)  

转载于:https://my.oschina.net/u/2247638/blog/875914

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值