迭代器

一、迭代器

1.什么是迭代器

  迭代:就是重复做一些事情,但是每一个重复都必须基于上一次重复的结果

  迭代器:迭代取值的工具

看看如下的案例,就不属于是迭代

n = 0
while True:
    print(n)

 迭代:

l=['a','b','c']
  def iterator(item):
      i=0
      while i < len(item):
          print(l[i])
          i+=1

2.为什么要有迭代器?

  迭代器提供一种不依赖索引取值的方式。基于索引的迭代器取值方式只适用于列表、元祖、字符串类型。

  而对于没有索引的字典、集合、文件则不适用

3.可以迭代取值的对象

在python中但凡有__iter__方法的对象,都是可迭代对象;

字符串、列表、字典、元祖、集合、文件,只有数字不是可迭代对象;

文件对象本身就是迭代器对象

num1=10
num2=10.1
s1='hello'
l=[1,2,3]
t=(1,2,3)
d={'x':1}
s2={1,2,3}
f=open('a.txt','w')

s1.__iter__()
l.__iter__()
t.__iter__()
d.__iter__()
s2.__iter__()
f.__iter__()

迭代器对象一定是可迭代对象。

迭代器的调用方式不是打印迭代器,而是执行双下next方法。否则打印出来的就是他对应的内存地址

info={'name':'wuxi','age':22,'is_beautiful':True,'sex':'male'}
info_iter=info.__iter__()            #加_iter_变成迭代器对象
print(info_iter)                    #打印出的是字典的内存地址
#<dict_keyiterator object at 0x0000000002927228>

#通过双下next方法取值
res1=info_iter.__next__()
print(res1)    #得到的是字典的K值
#next一次,打印一次结果。超过部分弹出警告!
res1=info_iter.__next__()
res2=info_iter.__next__()
res3=info_iter.__next__()
res4=info_iter.__next__()
res5=info_iter.__next__()
print(res1,res2,res3,res4,res5)
#超出部分,弹出StopIteration

for循环

for循环内部的本质
1.将in后面的对象调用__iter__转换成迭代器对象
2.调用__next__迭代取值
3.内部有异常捕获StopIteration,当__next__报这个错 自动结束循环

for循环其实就是循环打印next方法。for循环不许考虑是否取值超出范围。

for循环内部就是加入的while部分的代码:遇到警告就结束循环

info={‘wuxi’:‘name’}
iter_info=info.__iter__()#转成迭代器
while True:
    try:
        print(info_iter.__next__())#迭代器才可以执行next方法
    except StopIteration:
        break

知识点:

迭代器对象无论执行多少次__iter__方法,还是其本身(******)

print(f1 is f1.__iter__().__iter__().__iter__().__iter__())
#结果为True

4.文件对象

文件对象既是可迭代对象也是迭代器对象。因为既具有双下iter方法,也具有双下next方法

f1 = open('xxx.txt','r',encoding='utf-8')
iter_f = f1.__iter__()
#调用f1内置的__iter__方法
print(iter_f is f1)
#检测内存地址,结果是相同的

 迭代器方法读文件:

f1 = open('xxx.txt','r',encoding='utf-8')
# 调用f1内置的__iter__方法
# iter_f = f1.__iter__()
print(iter(f1).__next__(),end='')
print(iter(f1).__next__(),end='')
print(iter(f1).__next__(),end='')
print(iter(f1).__next__(),end='')
#结果是next一次,读一行

#111111111
#22222222
#33333333
#4444444

问:__iter__方法就是用来帮我们生成迭代器对象
而文件对象本身就是迭代器对象,为什么还内置有__iter__方法???

为了可以for循环迭代器。

for循环的三个步骤:1.将in后面的容器执行iter,再结合和控制报错的功能执行next。

如果迭代器无iter方法,那就报错了。

最后补充:迭代器执行iter,得到的还是本身

调用方法的书写形式:

s='hello'
print(len(s))

我发现。s.后面也有len方法。因此,可以这么写:

len(s)替换为.__len__()

s='hello'
print(s.__len__())
len(s)与s.__len__()是一样的

因此:

迭代器的调用可以这么写

s='hello world'
#调用:
iter(s).__next__()

总结迭代器的优缺点:

优点:

1、提供了一种通用的、可以不依赖索引的迭代取值方式
2、迭代器对象更加节省内存

缺点:

1.迭代器的取值不如按照索引灵活,同一个值只能取一次,只能从前往后一次取值

2.取完会报错:stopiteration

二、生成器

生成器就用用户自己定义的迭代器。在python中,内部有yeild方法的函数被称为生成器。跟普通函数不同的是,生成器是一个返回迭代器的函数,只能用于迭代操作,更简单点理解生成器就是一个迭代器。

在调用生成器运行的过程中,每次遇到 yield 时函数会暂停并保存当前所有的运行信息,返回 yield 的值, 并在下一次执行 next() 方法时从当前位置继续运行。调用一个生成器函数,返回的是一个迭代器对象。

def func():
    print('first')
    yield  666  # 函数内如果有yield关键字,那么加括号执行函数的时候并不会触发函数体代码的运行
    print('second')
    yield  777
    print('third')
    yield  888
    print('forth')
    yield
    yield
 

 生成器,本质就是迭代器,因此他的调用方式不是函数名加括号。直接打印函数名则为函数名的内存地址

 用生成器函数写range的原理

def my_range(start,stop,step):
    while start<stop:
        yield start
        start += step
res=my_range(2,12,3)
print(res.__next__())
print(res.__next__())
print(res.__next__())

 生成器表达式

从形式上来看,生成器表达式和列表推导式很像,仅仅是将列表推导式中的[]替换为(),但是两者差别挺大,生成器表达式可以说组合了迭代功能和列表解析功能。
生成器表达式可以认为是一种特殊的生成器函数,类似于lambda表达式和普通函数。但是和生成器一样,生成器表达式也是返回生成器generator对象,一次只返回一个值。

列表推导式的写法是
# 列表推导式的写法是:
squares_list=[i*i for i in range(5)] # 一次性返回整个list
print(squares_list)
[0, 1, 4, 9, 16]
 生成器表达式
# 生成器表达式:
squares2=(i*i for i in range(5)) # 生成器表达式一次返回一个值
print('生成器表达式:',squares2) # 生成器表达式: <generator object ..
print(next(squares2)) # 0这种写法等于squares2.__next__()
print(next(squares2)) # 1
print(next(squares2)) # 4

 现在这个需要一个一个print。用for循环可以自动打印,也不占内存

squares2=(i*i for i in range(5)) # 生成器表达式就是一个generator对象
for i in squares2:
    print('i: ',i)

 并且可以简写:

[print('i: ',i) for i in (i*i for i in range(5))]

三、python常用内置方法:

print(abs(-1))
print(all([1,'a',True])) # 列表中所有元素的布尔值为真,最终结果才为真
print(all('')) # 传给all的可迭代对象如果为空,最终结果为真

print(any([0,'',None,False])) #列表中所有元素的布尔值只要有一个为真,最终结果就为真
print(any([])) # 传给any的可迭代对象如果为空,最终结果为假

print(bin(11)) #十进制转二进制
print(oct(11)) #十进制转八进制
print(hex(11)) #十进制转十六进制

print(bool(0)) #0,None,空的布尔值为假

res='你好egon'.encode('utf-8') # unicode按照utf-8进行编码,得到的结果为bytes类型
res=bytes('你好egon',encoding='utf-8') # 同上
print(res)

def func():
pass
print(callable('aaaa'.strip)) #判断某个对象是否是可以调用的,可调用指的是可以加括号执行某个功能

print(chr(90)) #按照ascii码表将十进制数字转成字符
print(ord('Z')) #按照ascii码表将字符转成十进制数字


print(dir('abc')) # 查看某个对象下可以用通过点调用到哪些方法

print(divmod(1311,25)) # 1311 25

将字符内的表达式拿出运行一下,并拿到该表达式的执行结果
res=eval('2*3')
res=eval('[1,2,3,4]')
res=eval('{"name":"egon","age":18}')
print(res,type(res))
with open('db.txt','r',encoding='utf-8') as f:
s=f.read()
dic=eval(s)
print(dic,type(dic))
print(dic['egon'])


s={1,2,3}
s.add(4)
print(s)

不可变集合
fset=frozenset({1,2,3})

x=111111111111111111111111111111111111111111111111111111111111111111111111111111111111
# print(globals()) # 查看全局作用域中的名字与值的绑定关系
# print(dir(globals()['__builtins__']))
def func():
x=1
print(locals())
# func()
print(globals())

字典的key必须是不可变类型
dic={[1,2,3]:'a'}
不可hash的类型list,dict,set== 可变的类型
可hash的类型int,float,str,tuple == 不可变的类型
hash()

def func():
"""
帮助信息
:return:
"""
pass

# print(help(max))


len({'x':1,'y':2}) #{'x':1,'y':2}.__len__()

obj=iter('egon') #'egon'.__iter__()
print(next(obj)) #obj.__next__()

面向对象里讲
classmethod
staticmethod
property

delattr
hasattr
getattr
setattr

exec

isinstance
issubclass

原文地址:https://www.cnblogs.com/ZDQ1/p/11189493.html