不懂的问题:什么是协变、逆变?渐进式?
_T_co = TypeVar("_T_co", covariant=True) # Any type covariant containers.
- 作者:20岁爱吃必胜客(坤制作人),近十年开发经验, 跨域学习者,目前于海外某世界知名高校就读计算机相关专业。
- 荣誉:
阿里云博客专家认证
、腾讯开发者社区优质创作者,在CTF省赛校赛多次取得好成绩。跨领域学习
,喜欢摄影、弹吉他、咏春拳。文章深入浅出、语言风趣
;爱吃必胜客社区创立者,旨在“发现美 欣赏美
⭐️迭代器详解
Python迭代器是Python编程语言中非常常用的一种工具。它是访问容器(例如列表、元组等)
中的元素的一种方式
,可以逐个访问容器中的元素
,而不必
将整个
容器存储在内存
中。
Python迭代器可以被定义为:
- 一个实现了
__iter__()
方法的对象; - 通过调用
__next__()
方法来逐个访问容器中的元素。
🌟迭代器示例
下面是一个简单的Python迭代器示例:
class MyIterator: def __init__(self, lst): self.lst = lst# 列表 self.index = 0# 索引 def __iter__(self): return self def __next__(self): if self.index < len(self.lst): value = self.lst[self.index] self.index += 1 return value else: raise StopIteration
在这个示例中,我们创建了一个称为"MyIterator"的类,它包含了一个列表和一个索引值
。该类还实现了__iter__()
和__next__()
方法。
🌟__iter__()与__next__()方法解释
__iter__()
方法返回该对象本身
,因此可以直接对该对象使用for...in...
语句进行迭代。__next__()
方法则根据当前索引值来获取列表中的下一个元素
,如果已经到达列表末尾,则抛出StopIteration
异常。
以下是一个使用MyIterator迭代器的示例:
my_list = [1, 2, 3, 4, 5] my_iter = MyIterator(my_list) for item in my_iter: print(item)
执行结果为:
1 2 3 4 5
这是一个简单的例子,实际上Python迭代器可以应用
于许多不同类型的容器,包括列表、元组、字典以及文件等
。
🌟常用迭代器zip和enumerate
在Python标准库中,还提供了一些常用的迭代器,例如enumerate()
和zip()
。
从更深层次上来讲,Python迭代器是支持惰性计算(lazy evaluation)
的一种工具。惰性计算指的是在需要时才进行计算
,而非提前将所有的计算都执行完毕。对于大型数据集合,惰性计算可以节省内存
开销并提高程序性能。
Python迭代器的另一个特点是可逆性(reversibility)
,也就是说我们可以通过反向迭代器(reverse iterator)
来逆序
访问容器中的元素。Python标准库中提供了reversed()
函数用于创建反向迭代器
。以下是一个简单示例:
my_list = [1, 2, 3, 4, 5] for item in reversed(my_list): print(item)
执行结果为:
5 4 3 2 1
🌟itertools模块提供的各种迭代器类型
此外,Python迭代器还支持使用itertools
模块提供的各种迭代器类型,例如cycle()
、count()
和groupby()
等。
需要注意的是,Python 2.x版本中的迭代器实现与Python 3.x有所不同,因此在编写跨Python版本的代码时应当谨慎。
总的来说,Python迭代器是Python编程语言中非常强大和灵活的工具,可以应用于各种场景和数据类型,帮助我们更加高效地处理数据和任务。
🌟 源码
class Iterator(Iterable[_T_co], Protocol[_T_co]): @abstractmethod def __next__(self) -> _T_co: ... def __iter__(self) -> Iterator[_T_co]: ... class Iterable(Protocol[_T_co]): @abstractmethod def __iter__(self) -> Iterator[_T_co]: ...
🌟Python迭代器常见的用法
- 计算斐波那契数列
斐波那契数列是指从0和1开始,后续的每一项都是前面两项的和。使用Python迭代器可以很方便地计算斐波那契数列
。
class Fib: def __init__(self, max): self.max = max def __iter__(self): self.a = 0 self.b = 1 return self def __next__(self): fib = self.a if fib > self.max: raise StopIteration self.a, self.b = self.b, self.a + self.b return fib
以上代码定义了一个Fib类,实现了__iter__
和__next__
两个方法,该类实现了一个迭代器,可以使用for-in语句遍历所有小于max的斐波那契数列元素。
- 读取大型文件数据
当我们需要处理大量数据
时,将整个数据集加载到内存中可能会导致程序崩溃或效率低下。使用Python迭代器来处理大型文件数据非常理想,这种方式只在内存中维护当前处理的数据块,而不需要一次性读取整个文件。
with open('large_file.txt', 'r') as f: for line in f: process_line(line)
以上代码打开一个大型文件并使用for-in语句迭代遍历每一行数据,可以在不占用太多内存的情况下逐行处理文件。
- 实现生成器函数
除了使用类来定义迭代器,Python还支持使用生成器函数(generator function)来实现迭代器。生成器函数可以通过yield语句来产生值,当生成器被调用时,它将返回一个可迭代对象,使用for-in语句可以遍历这个可迭代对象。
def my_generator(max): for i in range(max): yield i for item in my_generator(5): print(item)
以上代码定义了一个生成器函数my_generator,使用yield语句来产生0~max-1的数字。使用for-in语句可以遍历这个生成器函数产生的可迭代对象,输出结果为:
0 1 2 3 4
⭐️迭代器与生成器的区别
在Python中,除了迭代器外,还有一种非常常见
的工具就是生成器(generator)
。两者都可以用yield
语句实现,但它们有一些区别。
迭代器
必须实现__iter__
和__next__
方法,而生成器
只需要实现一个yield语句
即可。生成器
可以保存状态
,每次调用yield语句
时会自动保存当前的局部变量和执行位置
,并在下一次调用时恢复执行状态
,从而实现了迭代器的功能。生成器
的主要作用是生成序列
,而迭代器则可以用于各种数据结构的遍历
,包括序列、映射、文件等。
🌟生成器的例子
def fibonacci(): a, b = 0, 1 while True: yield a a, b = b, a + b
以上代码定义了一个名为fibonacci的生成器
,它可以按照斐波那契数列的规律不断生成新的数值。我们可以使用for-in语句来迭代这个生成器,也可以使用next函数单独获取它的下一个值:
f = fibonacci() print(next(f)) # 输出 0 print(next(f)) # 输出 1 print(next(f)) # 输出 1 print(next(f)) # 输出 2
⭐️迭代器的内部实现
Python中的迭代器实际上是基于协议(protocol)实现
的,它需要满足两个条件:
- 实现
__iter__
方法并返回self
; - 实现
__next__
方法,并在每次调用时返回下一个值
,如果没有下一个值则抛出StopIteration
异常。
在Python中,任意对象只要满足以上两个条件就可以作为迭代器使用。以下是一个简单的自定义迭代器的例子:
class MyIterator: def __init__(self, data): self.data = data 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
以上代码定义了一个名为MyIterator的迭代器类,它包含了一个列表作为数据源
,
⭐️总结
__iter__()
:迭代器,生成迭代对象时调用
,返回值必须是对象自己,然后for可以循环调用next方法
__next__()
:每一次for循环都调用
该方法(必须存在
)
🌟__next__(),iter()详细解释
在 Python 中,使用 __next__()
和 __iter__()
方法可以创建一个迭代器对象。迭代器是一种特殊的对象,它允许我们逐个访问容器中的元素,而不必预先将整个容器加载到内存
中。
下面是 __next__()
和 __iter__()
的代码和讲解:
class MyIterator: def __init__(self, data): self.data = data self.index = 0 def __iter__(self): #@summary: 迭代器,生成迭代对象时调用, #返回值必须是对象自己,然后for可以循环调用next方法 return self def __next__(self): # @summary: 每一次for循环都调用该方法(必须存在) if self.index >= len(self.data): # 抛出 StopIteration 异常,表示迭代结束 raise StopIteration value = self.data[self.index] self.index += 1 return value
在上面的代码中,创建了一个名为 MyIterator
的迭代器类。该迭代器类包含以下两个方法:
__init__(self, data)
:构造函数,接受一个参数 data,即需要遍历的数据。__iter__(self)
:实现可迭代协议
,返回当前对象的迭代器对象
,即返回 self。__next__(self)
:实现迭代器协议
,返回容器中的下一个元素,如果没有更多元素,则抛出 StopIteration 异常。
现在,我们可以使用这个迭代器来遍历任何可迭代对象(如列表、元组、字典等)。下面是使用 MyIterator
迭代器来遍历一个列表的示例代码:
my_list = [1, 2, 3, 4, 5] my_iterator = MyIterator(my_list) for i in my_iterator: print(i)
在上面的代码中,我们首先创建了一个包含 5 个元素的列表 my_list
。然后,我们创建了一个 MyIterator
对象 my_iterator
,并将 my_list
作为参数传递给它。最后,我们使用 for
循环来遍历这个迭代器,从而遍历 my_list
中的所有元素。
通过上述示例代码可以看出,使用 __next__()
和 __iter__()
方法可以创建一个自定义的迭代器对象,并用于遍历任何可迭代的对象
。
🌟 魔法函数实现原理
Python中的“魔法函数”是一种特殊的函数
,其名称以双下划线“__”开头和结尾,例如“init”,“call”等,这些函数在Python的类定义中起到了特殊的作用。魔法函数的实现原理是利用了Python语言的一些特性,即“特殊方法解释器
”(SPECIAL METHOD LOOKUP)。
特殊方法解释器的工作方式为:当对象接收到一个消息
,但在该对象上没有对应的方法
时,会自动查找并调用该对象所在类中的特殊方法
,从而实现对该消息的处理。因此,魔法函数的作用就是为Python对象提供了默认的行为或操作
,从而方便我们对对象进行操作或控制。
下面以一个简单的例子说明魔法函数的实现原理
:
class MyClass: def __init__(self, x): self.x = x def __str__(self): return "MyClass with x = {}".format(self.x) # 创建一个MyClass对象 obj = MyClass(10) # 调用__str__魔法函数 print(obj)
上述代码定义了一个名为MyClass的类,其中包含了__init__和__str__两个魔法函数。__init__用于初始化对象的属性,__str__用于返回对象的字符串表示形式。在创建MyClass对象并输出时,会自动调用__str__函数并返回对象的字符串表示形式。
这就是魔法函数的实现原理:当创建对象时,会自动调用__init__
魔法函数进行初始化
操作;当需要获取对象的字符串
表示时,会自动调
用__str__
函数。通过使用魔法函数,我们可以很方便地对Python对象进行操作和控制,从而提高程序的效率和可维护性。
除了__init__和__str__这两个常见的魔法函数外,Python语言内置了大量的其他魔法函数,例如:
- call(self, *args, **kwargs): 使对象可以像函数一样被调用;
- getitem(self, key): 实现对象的索引访问;
- setitem(self, key, value): 实现对象的索引赋值;
- len(self): 返回对象的长度;
- add(self, other): 实现对象的加法运算;
- eq(self, other): 判断两个对象是否相等;
- …
通过定义这些内置的魔法函数,我们可以非常方便地实现自己的对象类型,支持各种操作和控制。例如,我们可以自定义一个矩阵类型,并实现其加法、乘法、转置等操作:
class Matrix: def __init__(self, data): self.data = data def __add__(self, other): result = [] for i in range(len(self.data)): row = [] for j in range(len(self.data[i])): row.append(self.data[i][j] + other.data[i][j]) result.append(row) return Matrix(result) def __mul__(self, other): result = [] for i in range(len(self.data)): row = [] for j in range(len(other.data[0])): s = 0 for k in range(len(self.data[i])): s += self.data[i][k] * other.data[k][j] row.append(s) result.append(row) return Matrix(result) def transpose(self): result = [] for i in range(len(self.data[0])): row = [] for j in range(len(self.data)): row.append(self.data[j][i]) result.append(row) return Matrix(result) def __str__(self): s = "" for i in range(len(self.data)): for j in range(len(self.data[i])): s += str(self.data[i][j]) + " " s += "\n" return s # 创建两个矩阵 m1 = Matrix([[1, 2], [3, 4]]) m2 = Matrix([[5, 6], [7, 8]]) # 执行加法和乘法操作 print(m1 +
🌟 我的故事
python学习之路任重而道远,要想学完说容易也容易,说难也难。 很多人说python最好学了,但扪心自问,你会用python做什么了?
刚开始在大学学习c语言,写一个飞行棋的小游戏,用dos界面来做,真是出力不讨好。 地图要自己一点一点画出来,就像这样:
================ | | | | |===============
从此讨厌编程,不想继续学下去。每次作业应付。 算法考试,数据结构考试随便背代码,只求通过。 最后呢?我学会变成了吗?只能对一些概念侃侃而谈,但真的会几行代码,能写出实用工具吗? 答案变得模糊。 所以我们要从现在开始,学好python,不要再糊弄下去!!!