一、变量与对象
-
Python 中一切皆为对象,数字是对象,列表是对象,函数也是对象,任何东西都是对象。
-
变量是对象的一个引用,又称名字或者标签,对象的操作都是通过引用来完成的。
-
赋值操作
=
就是把一个引用绑定到一个对象上。例如,[]是一个空列表对象,赋值给变量a,变量 a 是该对象的一个引用。
a = []
a.append(1)
二、对象的可变性
- 不可变对象:对象所指向的内存中的值不能被改变。不可变对象赋值给变量后,由于变量指向的值不可变,如果改变变量(准确的说是引用),相当于对变量进行了重新赋值,指向了内存中新的值。
- 变量a引用了内存中的对象:1
a = 1
- 对象1在内存中的地址
print(a, id(1))
print(a, id(a))
1 4496995664
1 4496995664
- 变量a重新赋值,引用了内存中的对象:2
a = 2
- 对象2在内存中的地址
print(a, id(2))
print(a, id(a))
2 4496995696
2 4496995696
2. 可变对象:对象所指向的内存中的值可以被改变。如果改变变量(准确的说是引用),实际上只是对其所指的值进行了变更,并没有产生新的值,通俗点说就是原地改变。
lt = [1, 2, 3]
print(id(lt))
4551719624
lt.append(100)
print(id(lt))
4551719624
- Python中,数值类型(int和float)、字符串str、元组(tuple)都是不可变类型,而列表(list)、字典(dict)、集合(set)是可变类型。
三、函数传参
-
Python函数中,参数传递的全部都是对象的引用,本质上是赋值操作,即把一个引用(变量)绑定到一个对象上。
-
参数是不可变对象时,不会对对象进行修改,相当于传递值。
-
参数是可变对象时,会对对象进行修改,相当传递引用。
-
在定义函数时,要注意函数的参数,传递的是值还是引用,特别是对于 默认参数 ,很容易导致潜在的bug。
四、函数的默认参数
- 默认参数是传递值时,仅仅在函数定义的时候赋值一次。
x = 8
def func(a, b=x):
return a, b
print(func(1))
(1, 8)
x = 20
print(func(1))
(1, 8)
- 示例中,默认参数
b
赋值为x
,x
为不可变对象字符串8
,当对x
重新赋值为20后,调用函数时,默认参数b
的值仍然为8
。 - 默认参数的值,通常应该是不可变的对象,比如None、True、False、数字或字符串。
- 默认参数是传递引用时,通常为空,比如空列表
[]
或空集合{}
,但在定义函数时,尽量设置为None,而不要让参数直接等于空列表或空集合。
def fun(a, b = []):
return b
f = fun(1)
print(f)
[]
f.append(100)
print(f)
[100]
- 像上述示例中,如果设置默认参数
b = []
,因为是可变对象,当默认参数b
的对象,在其他地方被修改后,下次调用这个函数时其默认参数b
已不再是空列表。 - 特殊情况下,比如在for循环中,调用默认参数为空列表
[]
或空集合{}
的函数,可以循环累积迭代结果。
五、匿名函数捕获参数值
-
lambda
表达式中的参数x
是一个自由变量, 是在执行时赋值(绑定),而不是定义时赋值(绑定),即lambda
表达式中的参数x
是执行时的值,这与函数的 默认参数 赋值不相同。
x = 10
a = lambda y: y + x
x = 20
print(a(10))
30
示例中,调用a(10)
时,x
取值为20
,而不是定义时的10
。
- 如果想让匿名函数,在定义时就捕获到参数值,将参数
x
定义成默认参数即可,例如:
z = 10
a = lambda x, z=z: x + z
print(a(2))
12
z = 7
print(a(2))
12
示例中,对变量z
重新赋值为7
,再次调用函数a(2)
时,匿名函数的参数z
的值仍
然为定义时的10
,而不是7
。
网友评论