目录
1.迭代器
迭代器的类型定义:
1.当类中定义了__iter__和__next__两个方法;
2.__iter__方法需要返回对象本身,即:self
3.__next__方法,返回下一个数据,如果没有数据了,则需要抛出一个StopIteration的异常。
官方文档:https://docs.python.org/3/library/stdtypes.html#iterator-types
下面我们来详解一下:
# 创建迭代器类型:
class myfunc(object):
def __init__(self):
self.counter = 0
def __iter__(self):
return self # 返回对象自身
def __next__(self):
self.counter += 1
if self.counter == 3:
raise StopIteration()
return self.counter
首先我们创建了一个名为myfunc的类,他继承自基类object,(object是所有类的基类,它是所有内置类型的父类,包括整数、字符串、列表等等。myfunc通过继承object
类,可以创建一个普通的Python类,可以使用一些通用的魔术方法,如__iter__
和__next__
。这样就可以创建一个迭代器对象,并实现自定义的迭代逻辑。
然后我们根据实例化创建一个迭代器对象并调用__next__方法:
# 根据类实例化创建一个迭代器对象
A = myfunc()
c1 = A.__next__()
c2 = A.__next__()
c3 = A.__next__() # 抛出异常
# 或者通过以下方式执行
c1 = next(A)
c2 = next(A)
c3 = next(A) # 抛出异常
我们也可以通过for循环进行打印输出:
c = myfunc()
for i in c:
print(i,end = " ")
# 结果输出 1 2
首先执行迭代器的对象的__iter__方法并获取返回值,把c这个实例对象传入给__iter__的self,又返回自己。他会一直反复地执行next(对象)。
2.生成器
定义:yiled为关键字,当yield出现在函数中,代表他为生成器函数,生成器函数后一加括号就是生成器对象。
以下是一个简单的实例:
# 创建生成器函数
def func():
yield 1
yield 2
# 创建生成器对象(内部是根据生成器类generator创建的对象,生成器内部也声明了:__iter__,__next__方法)
obj1 = func()
因为生成器内部也定义了__iter__与__next__,并且完全符合迭代器的定义规则,所以:
生成器是一种特殊的迭代器
他也可以通过 next取值,没有值也会抛出异常,也可使用for循环(这里不再举例展示)。
yield关键字
在Python中,yield
是一个关键字,用于定义生成器函数。生成器函数是一种特殊的函数,它可以暂停执行并返回一个中间结果,然后再次从上次暂停的地方继续执行。
具体来说,当一个函数中包含了yield
关键字时,它将返回一个生成器对象。生成器对象可以被迭代,每次迭代时会执行生成器函数中的代码,直到遇到yield
语句。yield
语句会将一个值返回给迭代器,并将函数的当前状态保存下来。下次迭代时,函数将从上次暂停的地方继续执行。
下面是一个简单的示例代码:
def generate_numbers(n):
for i in range(n):
yield i
# 使用生成器函数创建生成器对象
numbers = generate_numbers(5)
# 迭代生成器对象
for num in numbers:
print(num,end=" ")
# 输出结果为:0 1 2 3 4
generate_numbers
是一个生成器函数,它接受一个整数参数n
。- 在函数内部,使用
for
循环和yield
语句生成从0到n-1
的数字。 - 当生成器函数被调用时,它不会立即执行,而是返回一个生成器对象。
- 在
for
循环中,每次迭代会执行生成器函数中的代码,直到遇到yield
语句。 yield
语句将一个数字返回给迭代器,并且函数的当前状态被保存下来。- 下次迭代时,函数将从上次暂停的地方继续执行,生成下一个数字。
通过生成器函数和yield
语句,我们可以按需生成数据,而不是一次性生成所有数据,从而节省内存和提高效率。
3.可迭代对象
定义:如果一个类中有__iter__方法,且返回一个迭代器对象,则我们称这个类创建的对象为可迭代对象
简单的例子:
class func(object):
def __iter__(self):
return self # 返回可迭代对象或生成器对象
obj = func() # obj 是可迭代对象
for i in obj:
pass
可迭代对象是可以使用for来进行循环,在循环的内部其实是先执行__iter__方法,获取其迭代器对象,然后再在内部执行这个迭代器对象的next功能,逐步取值。实例说明:
# 创建迭代器类型:
class myfunc(object):
def __init__(self):
self.counter = 0
def __iter__(self):
return self # 返回对象自身
def __next__(self):
self.counter += 1
if self.counter == 3:
raise StopIteration()
return self.counter
class func(object):
def __iter__(self):
return myfunc() # 获取myfunc迭代器对象
A = func()
for i in A:
print(i,end=" ")
# 输出:1 2
在主程序中,我们创建了一个func的实例
对象,并使用for
循环迭代这个对象。由于func
对象是可迭代的,它会调用__iter__
方法,获取到一个myfunc
迭代器对象。然后,在每次迭代中,myfunc
对象会调用__next__
方法,返回一个递增的计数器值,并打印输出。
range功能
讲到实例对象,我们会想到range,其实类似a= range(100)这样的返回的a是一个可迭代对象,怎么证明呢?我们可以打开终端:
可以看到,他只有__iter__方法,没有__next__对象,所以他是可迭代对象。
而当执行a.__iter__并把它赋值给b,此时b就是一个迭代器对象,它自然就可以执行__next__方法了。
我们可以自定义range类:
class IterRange(object):
def __init__(self, num):
self.num = num
self.counter = -1
def __iter__(self):
return self
def __next__(self):
self.counter += 1
if self.counter == self.num:
raise StopIteration()
return self.counter
class Xrange(object):
def __init__(self, max_num):
self.max_num = max_num
def __iter__(self):
return IterRange(self.max_num)
obj = Xrange(100)
for i in obj:
print(i)
在主程序中,我们创建了一个Xrange
对象,传入最大值为100。然后,使用for
循环迭代这个对象。由于Xrange
对象是可迭代的,它会调用__iter__
方法,获取到一个IterRange
迭代器对象。然后,在每次迭代中,IterRange
对象会调用__next__
方法,返回一个递增的计数器值,并打印输出。
因此,运行上述代码会输出从0到99的整数。
常见的数据类型
a = list([10,20,30,40])
a 也是一个可迭代对象,因为在列表中声明了一个__iter__方法并且返回一个迭代器对象
终端如图:
列表,元祖,字典,这些常见的数据类型创建的一个对象都是可迭代对象
4.判断是迭代器or可迭代对象
如果你不确定某个对象是否是可迭代对象,迭代器,可以用代码判断
from collections.abc import Iterable, Iterator # 导入方法
d = [11, 22, 33]
print(isinstance(d, Iterator)) # False,判断是否是迭代器,判断依据是__iter__和__next__
print(isinstance(d, Iterable)) # True ,判断是否迭代,判断依据是是否有__iter__且返回迭代器对象
d1 = d.__iter__()
print(isinstance(d1, Iterator)) # True
print(isinstance(d1, Iterable)) # True
如果只要判断一个对象是否是可迭代对象,结合两者使用
d = [11, 22, 33]
if isinstance(d, Iterable) and isinstance(d, Iterator):
print("d是迭代器对象")
else:
print("d是一个可迭代对象")
# 输出 “d是一个可迭代对象”
关于迭代器,生成器,可迭代对象就讲解到这里,后续可能会更新,谢谢各位的支持!