1、对象
对于python来说一切皆对象,所有的变量都是内存中一个对象的“引用”。
类型是属于对象的,而不是变量的。而对象根据是否可变分为:
1、可变对象。例如list、dict、set
2、不可变对象。例如string、touple、numbers
而不可变对象中,有一部分当我们使用id()去查看他的内存地址,会发现,内存地址是相同的,另一部分却不相同。
#小的int类型相同
a=1
b=1
id(a)
Out[125]: 1529015408
id(b)
Out[126]: 1529015408
#大的int类型不相同
a=11111111111
b=11111111111
id(a)
Out[129]: 96958192
id(b)
Out[130]: 96958320
#tuple类型不相同
a=(1,2)
b=(1,2)
id(a)
Out[133]: 88059016
id(b)
Out[134]: 96127432
#str相同
a='absdf'
b='absdf'
id(a)
Out[137]: 96999888
id(b)
Out[138]: 96999888
这个是什么原因呢,假如说从节约内存角度来说的话,那么所有的不可变对象不应该都复用、相同吗?
Python里一切都是对象。所以1,2,3,4...这些整数也都是对象。这些基本的不可变对象在python里会被频繁的引用、创建,如果不找到好的办法的话,很容易让python引发效率瓶颈,所以python引入了整数对象池的机制。
- int中[-5, 256] 这些小整数被定义在了这个对象池里.所以当引用小整数时会自动引用整数对象池里的对象的.
- string对象也是不可变对象,python有个intern机制,简单说就是维护一个字典,这个字典维护已经创建字符串(key)和它的字符串对象的地址(value),每次创建字符串对象都会和这个字典比较,没有就创建,重复了就用指针进行引用就可以了。
- float类型可以认为每个赋值都是创建一个对象,因为float有点多,所以没必要和int一样了。
- tuple它是不可变对象,理应和int和string一样会做一个缓存,但是书上没有说明,于是看了看源码,发现tuple的数据结构很简单,简单到不能再简单,就是一个数组,里面是元组的迭代对象,这个对象指向的是各个元素.最关键的是元组没有实现intern机制!所以元组虽然是不可变对象,但它同时也是一个数组,这个数组和c里的数组一样,每次创建都会分配内存空间。
2、参数传递
当一个函数变量A==>指向内存地址1529015440,作为参数被传给一个函数func()时,函数func()会把这个变量A的对于对象的"引用"复制一份为变量B==>指向1529015440,放入函数中使用。
而在函数中进行修改这个变量对象B时,与外部的对象A没有任何关系。但是当内存地址1529015440为可变对象时,修改了对象B就会修改掉这个内存地址对象,从而修改掉A;如果内存地址1529015440为不可变对象时,修改对象B就会将B指向内存地址1529015440更改为新的内存地址比如1529015444,此时A依然指向内存地址1529015440,A不会发生变化。
A = 1
B = [1,2]
def func(key):
print(id(key))
if isinstance(key, list):
key[0]=2
else:
key=2
print(id(key))
id(A)
Out[9]: 1529015408
func(A)
1529015408
1529015440
id(B)
Out[12]: 96144136
func(B)
96144136
96144136
参考1:https://www.stackoverflow.com
参考2:https://www.jianshu.com