Python中可变和不可变对象的深入讲解

1. 引言

Python是一门支持面向对象编程(Object-Oriented Programming,OOP)的编程语言,这就要求我们必须要熟练掌握Python中的对象概念,了解Python中的可变对象和不可变对象的特性。本文将围绕Python中可变和不可变对象的特性做一个深入讲解,以期读者深入理解Python对象模型。

2. 可变对象和不可变对象的概念

Python中一切皆为对象,包括基本数据类型(如int、float等)及复杂数据类型(如list、tuple、dict等)。在Python的官方文档中,将所有的对象分为两种类型:可变对象和不可变对象。

2.1 不可变对象的特性

不可变对象在创建后其内部状态不可改变,这里的内部状态指的是对象属性值或对象自身,使得对象的身份(id)不会被改变,但对象的值(value)可以被改变。常见的Python不可变对象类型包括int、float、bool、str、tuple等。

# int类型

a = 1

b = a

print('a:', id(a), 'b:', id(b)) # a:140720686417600 b:140720686417600

a += 1

print('a:', id(a), 'b:', id(b)) # a:140720686417632 b:140720686417600

从上面的代码可以看出,对于一个int类型的不可变对象,当其值发生改变时(a += 1),其内部状态也发生了改变,这种改变并不是在原对象上进行,而是新创建了一个对象,旧对象已经被丢弃了,新的对象与原对象id不同,且值发生了改变,但原对象的id并未改变。

2.2 可变对象的特性

相比不可变对象,可变对象在创建后其内部状态可以改变,包括对其属性的增删改查、对其变量的重新赋值、对其元素的改变等操作。常见的Python可变对象类型包括list、dict、set等。

# list类型

a = [1, 2, 3]

b = a

print('a:', id(a), 'b:', id(b)) # a:1969986184768 b:1969986184768

a[0] = 4

print(a, b) # [4, 2, 3] [4, 2, 3]

print('a:', id(a), 'b:', id(b)) # a:1969986184768 b:1969986184768

从上面的代码可以看出,对于一个list类型的可变对象,对其元素进行修改时相当于是对原对象进行的操作,原对象的值和id都没有发生改变。

3. 实例演示

接下来,我们将通过一些实际的例子来探究可变对象和不可变对象的特性。

3.1 列表、元组和可变性

在Python中,列表和元组都可以包含多个值,但它们有一个重要的区别:列表是可变的,而元组是不可变的。以下是一个列表和元组的简单示例:

# list和tuple的比较

list1 = [1, 2, 3]

tuple1 = (1, 2, 3)

list1[0] = 4

print(list1) # [4, 2, 3]

# tuple1[0] = 4 # TypeError: 'tuple' object does not support item assignment

print(tuple1)

从上面的代码可以看出,虽然list和tuple都包含了相同的元素,但是我们只能修改list中的元素,而不能修改tuple中的元素。这是由于在Python中,元组是不可变对象,而列表是可变对象,列表的元素可以更改。

3.2 字典和可变性

在Python中,字典是一种映射类型,它包含一个键和一个对应的值。与列表不同,字典中的元素是无序的。以下是一个简单的字典示例:

# 字典和可变性

dict1 = {'a': 1, 'b': 2, 'c': 3}

dict2 = dict1

dict1['a'] = 4

print(dict1) # {'a': 4, 'b': 2, 'c': 3}

print(dict2) # {'a': 4, 'b': 2, 'c': 3}

从上面的代码可以看出,尽管我们只修改了字典的一个元素,但是它也影响了两个变量(dict1和dict2)的值。这是因为字典是可变对象,所以当我们改变其中的一个元素时,改变将反映在所有引用该对象的变量中。

3.3 函数调用中的可变性问题

在Python中,函数调用中的参数传递和对象赋值操作非常相似。在函数调用时,我们可以将一个对象分配给参数,并且在函数内部可以访问该对象。

# 函数调用中的可变性问题

def change_list(lst):

lst[0] = 5

a = [1, 2, 3]

change_list(a)

print(a) # [5, 2, 3]

从上面的代码可以看出,我们将一个对象(一个列表)传递给函数,并在函数内部更改该对象。由于列表是可变对象,所以调用函数后,原始列表的值被修改,并且打印结果中包含了更改后的列表。

4. 总结

本文我们讲解了Python中可变对象和不可变对象的特性,并通过实例讲解了列表和元组、字典以及函数调用中的可变性问题。了解可变和不可变对象对于Python程序员来说至关重要,因为它涉及到对象在内存中的存储方式,对于优化程序的性能和避免错误都非常有帮助。

后端开发标签