理解python中的可变类型、不可变类型及如何改变函数中的参数

可以将python中常见数据类型按照可变与不可变大致分为两类

可变类型 不可变类型
列表、字典、类 数值型、字符串、元组

理解可变与不可变
  熟悉python的都知道,像字符串和元组创建之后是无法更改的,如果更改那么就只能替换掉,也就是说丢弃原来的存储空间,将变量名链接到新的空间中。而像list和dict是支持增删改的。
以list和tuple增加元素的操作为例(用内置函数 id(var) 来查看变量内存地址)

x   = [1,2]
print('mutable var:list')
print('original:', id(x))
x.append(10)
print('modifed:', id(x))

print('\n')

print('immutable var:tuple')
y = tuple([1, 2])
print('original:', id(y))
y+=(10,)
print('modified:', id(y))

reuslt:

mutable var:list
original: 140611793965640 [1, 2]
modifed: 140611793965640 [1, 2, 10]


immutable var:tuple
original: 140611829612104 (1, 2)
modified: 140611793818824 (1, 2, 10)

由结果可见,虽然都添加了一个元素,但是list的存储首地址不变。tuple类型的变量也修改成功,但是通过替换来实现,也就是变量指向新的存储地址。

如何修改函数参数
  来看两个例子

#向函数传入一个不可变类型变量作为参数
var = 10
def func(var):
   var = 20
   print('var in func:', var)
   
print('global var:', var)
func(var)
print('global var after func modified:', var)
global var: 10
var in func: 20
global var after func modified: 10

上述例子说明,对传入函数的不可变类型变量进行更改,并不影响函数作用域之外该变量的原始值。

那么再来看看传入可变变量是什么情形

#传入一个可变变量
lst = [1,2]

def func(var):
    var.append(100)
    print('var in func:', var)
    
print('global var:', lst)
func(lst)
print('global var after func modified:', lst)

result

global var: [1, 2]
var in func: [1, 2, 100]
global var after func modified: [1, 2, 100]

从结果来看,在函数中对传入的list变量进行修改,使得函数作用域之外的变量也发生了改变。这与第一个实验传入不可变变量的结果正好相反。

初步结论: 从上述两个实验中可以初步得出一个结论,在函数中修改不可变变量,不会影响函数之外的变量,而修改可变变量能够影响函数之外的变量。

那么再来看一个例子

#传入一个可变变量
lst = [1,2]

def func(var):
    var = list([100,100])  #区别在这里
    print('var in func:', var)
    
print('global var:', lst)
func(lst)
print('global var after func modified:', lst)

result

global var: [1, 2]
var in func: [100, 100]
global var after func modified: [1, 2]

上述代码将函数中的增填元素的操作变成重新赋值。结果并不影响函数外的变量值,这里似乎与初步得出的结论相矛盾。
其实大体上初步结论是正确的,但是函数传参涉及到副本的创建与拷贝问题,所以与结论有一定的出入。具体将在下一节变量的存储形式与拷贝问题中提到(python中变量的存储与拷贝)。(顺便提一句,说tuple是不可修改的存在某种程度的不严谨,如果tuple中包含可变类型,针对可变类型还是可以修改的)

ps…作者认知有限,如有错误或者疑问请留言联系我,谢谢阅读。

你可能感兴趣的:(python编程)