Python 中的可变和不可变
本文解释了 Python 中的可变和不可变。
YouTube Video
Python 中的可变和不可变
“可变”和“不可变”指的是对象的可变性。理解这一点有助于避免意外的错误和高效的内存管理。
什么是可变的?
可变对象可以在创建后更改其内部状态。
主要的可变数据类型
listdictset- 用户定义的类(如果其属性是可修改的)
示例:修改列表
1numbers = [1, 2, 3]
2numbers[0] = 100
3print(numbers) # [100, 2, 3]列表是一个可变对象,其元素可以自由修改。
什么是不可变的?
不可变对象在创建后不能被更改。尝试修改它们会导致创建一个新对象。
主要的不可变数据类型
intfloatstrtupleboolfrozenset
示例:修改字符串
1text = "hello"
2# text[0] = "H" # TypeError: 'str' object does not support item assignment
3
4text = "H" + text[1:] # Creates a new string
5print(text) # "Hello"字符串是不可变的,因此您无法部分修改它们。
可变与不可变的比较
1# Mutable example
2a = [1, 2, 3]
3b = a
4b[0] = 100
5print(a) # [100, 2, 3] -> a is also changed
6
7# Immutable example
8x = 10
9y = x
10y = 20
11print(x) # 10 -> x is unchanged正如你从这个例子中看到的,可变对象是通过引用共享的,因此它们可以影响其他变量。另一方面,不可变对象在重新赋值时会创建新的实例,原始值不会受到影响。
使用 id() 检查内部行为
在 Python 中,你可以使用 id() 函数查看对象的 ID。对象的 ID 类似于内存地址。
1# Immutable int behavior
2a = 10
3print(id(a)) # e.g., 140715920176592
4a += 1
5print(id(a)) # e.g., 140715920176624 -> ID has changed
6
7# Mutable list behavior
8b = [1, 2, 3]
9print(id(b)) # e.g., 2819127951552
10b.append(4)
11print(id(b)) # Same ID -> only the content has changed如图所示,对于不可变类型会创建一个新对象,而可变类型则会就地修改。
与可变和不可变对象相关的函数与注意事项
当将可变对象传递给函数时,原始数据可能会被修改。
示例:一个修改列表的函数
1def modify_list(lst):
2 lst.append(100)
3
4my_list = [1, 2, 3]
5modify_list(my_list)
6print(my_list) # [1, 2, 3, 100]示例:一个修改数字的函数
另一方面,尝试修改不可变对象会创建一个新对象。
1def modify_number(n):
2 n += 10
3
4my_number = 5
5modify_number(my_number)
6print(my_number) # 5 -> unchanged实际注意事项
避免将可变对象用作默认参数
1# Bad example
2def add_item(item, container=[]):
3 container.append(item)
4 return container
5
6print(add_item(1)) # [1]
7print(add_item(2)) # [1, 2] -> unintended behavior
8
9# Good example
10def add_item(item, container=None):
11 if container is None:
12 container = []
13 container.append(item)
14 return container
15
16print(add_item(1)) # [1]
17print(add_item(2)) # [2]由于默认参数仅在函数定义时计算一次,使用可变对象可能会导致意外的副作用。
- 在第一个例子中,每次调用
add_item时都会使用同一个列表对象。第二次调用add_item(2)时,之前添加的1仍然在列表中,因此结果是[1, 2]。 - 在改进的例子中,
None被用作默认值,如果参数为None,则会在函数内部创建一个新的列表。这样可以确保每次调用函数时都会创建一个新的列表,因此之前的结果不会影响后续的调用。
避免使用像列表或字典这样的可变对象作为默认参数;相反,应该使用 None 并在函数内部进行初始化。这是 Python 中一个基本且重要的最佳实践。
总结
要深入理解 Python 的变量和数据类型,掌握可变与不可变之间的区别非常重要。理解这些特性可以帮助你避免代码中的意外行为,并编写更健壮和更易读的程序。
您可以在我们的YouTube频道上使用Visual Studio Code跟随上述文章进行学习。 请也查看我们的YouTube频道。