不废话,直接干货
1.了解一下python的内存机制a=1
b=1
id(a)=id(b) #短的字符串,数字python在内存中是一个对象
a=[]
b=[]
id(a)!=id(b) #字典,数组这样的对象在内存中python会创建两个不同的对象
a="new a string"
b="new a string"
id(a)!=id(b) #长的字符串python在内存中同样会创建两个不同的对象
2.python中万物皆对象(很简单的一句话,也是最核心的一句话)
# 不可变类型 >>>a = 'wangjunjie' >>>id(a) 4324743920 >>>a += '0817' >>>id(a) 4324744944 >>>a = a + '0817' >>>id(a) 4324750584 # 可变类型 >>>my_list = [1, 2, 3] >>>my_list [1, 2, 3] >>>id(my_list) 4324743240 >>>my_list += [4, 5, 6] >>>my_list [1, 2, 3, 4, 5, 6] >>>id(my_list) 4324743240 >>>my_list = my_list + [7, 8, 9] >>>my_list [1, 2, 3, 4, 5, 6, 7, 8, 9] >>>id(my_list) 4324744136
简单总结上面显示结果的几个重要结论:
1.变量分为不可变类型和可变类型,字符串、元组、整型、浮点型等数字都是不可比那类型,字典、列表、集合是可变类型
2.对于不可变类型,无论是执行a = a+b还是a += b,a的内存地址都会变,可以理解为生成了新的变量;
那对于可变类型,执行my_list = my_list + new_list时,my_list的内存地址发生变化,即my_list变成了一个新的变量;但是在执行my_list += new_list的时候,my_list内存地址不会发生变化,即没有生成新的变量,这种方法效果等类似于列表的extend操作。
**这里有一个例外的类型,小伙伴们要重视,那就是str,str是有__iadd__方法的,只不过不像列表一样地址ID不变,str的地址是会变的
3.两种方法的python底层原理从方法的背后魔法方法可以清楚的解释这种现象:
+=背后的魔法方法是__iadd__
+背后的魔法方法是__add__
如果一个类,没有实现__iadd__方法的话,python就会退一步调用__add__方法
总体来说,可变类型都有__iadd__方法,而不可变类型没有__iadd__方法
为了方便记忆,我自己是这么记的:=单独出现的作用一般是赋值操作,所以a = a + b实际上就是python帮我们算出来a + b的值之后赋值给了变量a,在python眼中,这两个a本身就是两个毫无关联的对象。
>>>my_tuple = (1, 2, [3, 4]) >>>my_tuple[2] += [5, 6]
思考一下此时my_tuple的值
>>> my_tuple = (1, 2, [3, 4]) >>> my_tuple[2] += [5, 6] Traceback (most recent call last): File "", line 1, in TypeError: 'tuple' object does not support item assignment >>> my_tuple (1, 2, [3, 4, 5, 6]) >>>
猜对了吗?实际上,这里面有两个点,第一个是元组不可变,python确实报错了,但是my_tuple中的列表呢?第二个是实际上元组中的列表只是一个列表对象内存地址的引用而已,所以在执行my_tuple[2] += [5, 6]时候,列表的值被改变了!
注意一下:以上这个报错用my_tuple[2].extend([5, 6])不会报错,这并不违背元组是不可变的原则,因为引用地址确实没变,只不过地址里面的值,已经发生变化了!
5.* 和 *=其实,这两个和+、+= 基本一样,只不过背后的魔法方法是__imul__和__mul__而已,就这么简单~



