我们可以通过下面的例子来感受上面的话
52454056
52454032
id()是一个内置函数,可以返回对象的唯一标识
同样的变量x进过经过加操作后地址改变了。
x=1
y=1
z=1
print id(x)
print id(y)
print id(z)
56976040
56976040
56976040
可以发现虽然变量名不同但是地址确实一样的。
这种特性是不是很想别的语言中的字符串。我们称有这种特性的变量为不可变变量(值一旦改变就会占据新的内存空间)。python中的不可变变量有如下
不可变(immutable):int、字符串(string)、float、(数值型number)、元组(tuple),None
优点:
这样可以减少重复的值对内存空间的占用。
缺点:
操作之后就开辟内存的特性。执行效率会有一定程度的降低。
我再来看看可变变量
x=[]
print id(x)
x.append(1)
print id(x)
49918024
49918024
可以看见可变量和别的语言是一样的。内存是不会改变的
x=[]
y=[]
z=[]
print id(x)
print id(y)
print id(z)
62566472
62669960
62671368
可以看见对于可变变量 ,创建一次就开辟一次地址,不会引用同一块内存
可变(mutable)变量:字典型(dictionary)、列表型(list)
python 中不可变量为按值传递,可变变量按引用传递
def f(l=[]):
l.append(1)
return l
print f()
print f()
print f()
[1]
[1, 1]
[1, 1, 1]
这是为什么呢?首先我们要知道python 你看见的任何东西都是对象。函数也不例外,默认参数有如下特点
现在我们来验证上上面的结果。
参数的默认值就存在__defaults__中。
def f(l=[]):
l.append(1)
return l
f()
print f.__defaults__
f()
print f.__defaults__
f()
print f.__defaults__
([1],)
([1, 1],)
([1, 1, 1],)
可以看见参数的默认值就在其中,但是是不是同一个呢,现在我们来看看地址
def f(i=1):
print id(i)
i+=1
print id(i)
return i
f()
print '默认值地址:%s'%id(f.__defaults__[0])
f()
print '默认值地址:%s'%+id(f.__defaults__[0])
f()
print '默认值地址:%s'%+id(f.__defaults__[0])
56976040
56976016
默认值地址:56976040
56976040
56976016
默认值地址:56976040
56976040
56976016
默认值地址:56976040
可以发现函数定义时默认值就已近存在在__defaults__中了。在调用函数时我们的参数变量就会被赋值为这个__defaults__[0]地址。当.__defaults__[0]是不可变变量时
我们对参数变量进行修改时我们的参数变量地址会变化。这个和我们的逻辑思维一致
可变变量就不一样了!
def f(l=[]):
print id(l)
l.append(1)
print id(l)
return l
f()
print '默认值地址:%s'%id(f.__defaults__[0])
f()
print '默认值地址:%s'%id(f.__defaults__[0])
f()
print '默认值地址:%s'%id(f.__defaults__[0])
58904648
58904648
默认值地址:58904648
58904648
58904648
默认值地址:58904648
58904648
58904648
默认值地址:58904648
因为可变变量的特性。我们在更改时时不会换地址的,所以我们一直都是在更改__defaults__[0] 。这种特性在默认参数中不是我们想要的。我们用如下的代码完成任务
def f(l=None):
print id(l)
l=[]
l.append(1)
print id(l)
return l
print f()
print '默认值地址:%s'%id(f.__defaults__[0])
print f()
print '默认值地址:%s'%id(f.__defaults__[0])
print f()
print '默认值地址:%s'%id(f.__defaults__[0])
1792584792
47296584
[1]
默认值地址:1792584792
1792584792
47296584
[1]
默认值地址:1792584792
1792584792
47296584
[1]
默认值地址:1792584792
因为None是不可变变量,所以我对他的所有操作都是在新的内存中完成的。这其实也就是None的作用
class b:
x = []
def set(self):
self.x.append(1)
def get(self):
return self.x
for i in range(3):
a = b()
print b.__dict__
a.set()
a.get()
{'x': [], '__module__': '__main__', 'set': , '__doc__': None, 'get': }
{'x': [1], '__module__': '__main__', 'set': , '__doc__': None, 'get': }
{'x': [1, 1], '__module__': '__main__', 'set': , '__doc__': None, 'get': }
可以发现每次创建类b时,其中的x都是不一样的。这也是因为可变变量的原因
而对于不可变变量就不一样了
class b:
x = 1
def set(self):
self.x+=1
def get(self):
return self.x
for i in range(3):
a = b()
print b.__dict__
a.set()
print a.get()
{'x': 1, '__module__': '__main__', 'set': , '__doc__': None, 'get': }
2
{'x': 1, '__module__': '__main__', 'set': , '__doc__': None, 'get': }
2
{'x': 1, '__module__': '__main__', 'set': , '__doc__': None, 'get': }
2
可以发现,原先的”全局变量“现在已经不是全局变量了