一、可变对象与不可变对象
在Python中,对象可以分为可变对象和不可变对象。可变对象是指在创建后其值可以更改,而不可变对象则是指创建后其值不可更改。
常见的可变对象包括列表(List)、字典(Dict)和集合(Set),而不可变对象包括数值类型(int、float、complex)、布尔类型(bool)、字符串(str)、元组(tuple)和不可变集合(frozenset)等。
区别:
1、内存层面:
在内存层面,可变对象和不可变对象的主要区别在于其值存储的方式。不可变对象的值存储在对象的固定内存地址中,一旦创建就不能更改。而可变对象的值存储在可变的内存地址中,其内部结构也可能发生改变。
下面示例代码可以看到,在创建一个不可变对象(比如数字)时,其内存地址是不变的:
a = 10
print(id(a)) # 输出:140734751454848
a = 20
print(id(a)) # 输出:140734751455168
而在创建一个可变对象(比如列表)时,其内存地址可以发生变化:
li = [1, 2, 3]
print(id(li)) # 输出:140734751657672
li.append(4)
print(id(li)) # 输出:140734751657672
2、源码层面:
在源码层面,可变对象和不可变对象的主要区别在于其是否支持原处修改(in-place modification)。不可变对象不支持原处修改,而可变对象则支持。
下面的示例代码可以看到,尝试在一个不可变对象(比如元组)中进行修改会导致异常:
tup = (1, 2, 3)
tup[0] = 4 # 报错:TypeError: 'tuple' object does not support item assignment
而在一个可变对象(比如列表)中进行修改则不会出现这个问题:
li = [1, 2, 3]
li[0] = 4
print(li) # 输出:[4, 2, 3]
二、迭代器和可迭代对象
1、迭代器
Python迭代器是一种可以遍历容器对象(例如列表、元组和字典)中的元素的对象。从源代码实现的角度来看,Python中的迭代器是一种实现了特定协议的对象。这个协议包括两个方法:
__iter__()
和__next__()
。实现了这两个方法的对象就是迭代器。
__iter__()
方法返回一个迭代器对象自身,这个对象将被用来遍历容器中的元素。
__next__()
方法返回容器中的下一个元素。当迭代器已经到达了容器的末尾,__next__()
方法将会抛出一个StopIteration
异常。
从内存分配的角度来看,迭代器是一种能够更加高效地遍历容器中的元素的方式。与列表等容器对象不同,迭代器仅需为当前迭代的元素分配内存,而不是为容器中的所有元素分配内存。这意味着迭代器在处理大量数据时可以节省内存,并且可以更快地处理大型数据集。
在Python中,可以使用iter()
函数来创建一个迭代器对象。例如,下面的代码创建了一个迭代器对象,并使用next()
函数遍历了它的元素:
my_list = [1, 2, 3, 4, 5]
my_iter = iter(my_list)
print(next(my_iter)) # 输出:1
print(next(my_iter)) # 输出:2
print(next(my_iter)) # 输出:3
当容器中的元素已经被遍历完时,再调用next()
函数将会触发StopIteration
异常。在实际编程中,我们通常使用for
循环语句遍历迭代器中的元素,这样就可以避免StopIteration
异常的出现。例如:
my_list = [1, 2, 3, 4, 5]
for item in my_list:
print(item)
这段代码中,my_list
对象被转换成迭代器对象,并使用for
循环语句遍历其中的元素。在遍历完所有元素后,循环语句自动结束,不会抛出StopIteration
异常。
2、可迭代对象
可迭代对象是指能够被迭代的对象,例如列表、元组、字典、集合等。从源代码实现的角度来看,Python中的可迭代对象在实现上是通过实现__iter__()方法和__next__()方法来完成的。
iter()方法定义了可迭代对象应该如何被迭代。该方法应该返回一个迭代器对象。迭代器对象需要实现__next__()方法,返回下一个迭代值,如果没有更多的值可以迭代,应该抛出StopIteration异常。
例如,以下是一个实现了__iter__()方法和__next__()方法的简单的可迭代对象:
class MyIterable:
def __init__(self):
self.data = [1, 2, 3]
self.index = 0
def __iter__(self):
return self
def __next__(self):
if self.index == len(self.data):
raise StopIteration
value = self.data[self.index]
self.index += 1
return value
这个对象可以使用for循环来迭代:
for value in MyIterable():
print(value)
输出结果为:
1
2
3
需要注意的是,Python中的可迭代对象不一定需要实现__next__()方法,如果一个对象只实现了__iter__()方法,那么它就是一个迭代器对象,而不是可迭代对象。但是,实现了__iter__()方法的可迭代对象会在每次迭代时返回一个新的迭代器对象,因此,如果要在多个迭代中共享迭代状态,应该实现一个独立的迭代器对象并返回它。