迭代器/for循环本质/生成器/常用内置方法

一.迭代器

1.1迭代器的定义:

迭代器:迭代取值的工具

迭代;更新换代的过程,每次迭代都是基于前一次迭代的基础

1.2迭代器的作用:

  提供了一种不依赖索引取值的方法

1.3可迭代对象/迭代器对象

  可迭代对象:内置有__iter__方法的叫做可迭代对象

  迭代器对象:内置有__iter__方法,且还有__next__方法的叫做可迭代对象

  可迭代对象----->__iter__------>迭代器对象

ps:1.迭代器对象一定是可迭代对象,但是可迭代对象不一定是迭代器对象

  2.迭代器对象执行内置的__iter__之后还是本身,没有任何变化 

f = open('xxx.txt','w',encoding='utf-8')
print(f is f.__iter__().__iter__().__iter__())
# True 因为文件本身是一个迭代器,对其执行内置的__iter__后还是其本身

  迭代器的取值特点:只能往前取值,不能后退,不能取指定值,取完值后会报错(StopIteration)

d = {
    'zhang':10000,
    'wang':8000,
    'li':7000
}
res = d.__iter__()  # 将d转化成迭代器对象
print(res.__next__())  # 迭代取值 zhang
print(res.__next__())  # 迭代取值 wang
print(res.__next__())  # 迭代取值 li
print(res.__next__())  # 报错 StopIteration

print(d.__iter__().__next__())  # zhang
print(d.__iter__().__next__())  # zhang
print(d.__iter__().__next__())  # zhang
print(d.__iter__().__next__())  # zhang
#出现上述结果的原因是每次都重新生成的迭代器,所以每次取值都为zhang

 迭代取值的优缺点:

  优点:1.不依赖索引取值

     2.内存中永远只占据一份空间,不会导致内存的溢出

  缺点:1.不能指定取值

     2.将迭代器中的值取完后若继续取值会报错StopItertion

二.for循环的本质

  for循环的内部本质:

    1.将in后面的对象(可迭代对象/迭代器对象)执行内置的__iter__转换成迭代器对象

    2.对产生的迭代器对象执行内置的__next__进行迭代取值

    3.内部存在异常捕获StopItertion,当__next__报这个错的时候,自动结束循环(迭代器内部值被取完)

  如何处理取值中的异常:

d = {
    'zhang':10000,
    'wang':8000,
    'li':7000
}
res = d.__iter__()
while True:
    try:
        print(res.__next__())
    except StopIteration:
        print('迭代器中没有值了')  # 当迭代器中没有值时会执行这行代码,这样可以使迭代器在取值使不报错,咋没值时直径跳出循环
        break  

   

三.生成器

  本质:用户自己定义的迭代器,其本质就是迭代器

  特点:惰性运算,开发者自己定义

  生成器函数:函数内部包含有yield关键字.

ps:1.如果一个函数内含有yield关键字,那么加括号执行函数的时候并不会除法函数的运行

  2.yiled后跟的值就是调用迭代器__next__方法你能得到的值

  3.yiled既可以返回一个值也可以返回多个值,返沪i多个值以元组的形式返回

def func():
    print('first')
    yield  1 
    print('second')
    yield  2
    print('third')
    yield  3,'a','b'
    print('forth')
g = func()
print(g.__next__())  #  first 1
print(g.__next__())  # second 2
print(g.__next__())  # third (3,'a','b')
print(g.__next__())  # StopIteration

ps:每执行依次__next__从g中取出一个值,会暂停在yield处,直至下次执行__next__直至迭代器中没有值报错

yiled支持外界为其传参:(形参,闭包)

def dog(name):
    print('%s 准备开吃'%name)
    while True:
        food = yield
        print('%s 吃了 %s'%(name,food))
g = dog('egon')  # 函数体代码中含有yiled的,函数名加括号不会调用函数而是将函数转化成生成器  
g.__next__()  # 必须先将代码运行至yield 才能够为其传值  egon 准备开吃
g.send('狗不理包子')  # 给yield左边的变量传参  触发了__next__方法  egon 吃了 狗不理包子

ps:return和yiled的异同点

  相同:1.都有返回值,且都可以返回都和值以元组的形式

  不同:1.return只能返回一次值,返回后函数立即结束,yiled可以返回多次

     2.yiled可以接收外界传值

生成器表达式:

res = (i for i in range(10))  # <generator object <genexpr> at 0x00000230060FF048>

 ps:生成器不会主动运行任何一行代码,必须通过内置的__next__方法来取值,且每运行一次只取出其中的一个值

print(res.__next__())  # 0
print(res.__next__())  # 1
print(res.__next__())  # 2  

 引用场景:取一个较大的容器类型,在python2中

python3中

这样可以节省内存,当需要值得时候生成器才会产生需要得数量,以节约内存,防止内存溢出

示例:

def add(n,i):
    return n+i
def test():
    for i in range(4):
        yield i
g=test()

for n in [1,10]:
    g=(add(n,i) for i in g)  # 第一次for循环g=(add(n,i) for i in test())
                             # 第二次for循环g=(add(n,i) for i in (add(n,i) for i in test()))  此时n=10
res=list(g)  # 从生成器中取值
"""
在test()函数中进行for循环取值,第一个值为0,则i为0,此时n为10,执行add函数,得出结果为10在执行for循环取出值为10,执行add函数,得出第一次结果为20.
以此类推,进行四次test()分别输出0,1,2,3.右侧add函数输出结果为10,11,12,13.左侧add输出结果为20,21,22,23       

  

四.常用得内置函数

# abs取绝对值
print(abs(-2))  # 2
#all后跟得可迭代对象中若有一个元素为false则整个为false
a=[1,2,3,0]
print(all(a))  # False
#any后跟得可迭代对象中若有一个元素为True则整个为True
b=[0,{},1]
print(any(b))  # True
#bin10进制转2进制
print(bin(17))  # 0b10001
#hex10进制转16进制
print(hex(17))  # 0x11
#oct10进制转8进制
print(oct(17))  # 0o21
# bool判断bool值
print(bool(1))  # True
#bytes转换成二进制类型
s='qwe'
print(bytes(s,encoding='utf-8'))  # b'qwe'
#callable可调用的(加括号执行相应功能得,函数)
#chr
print(chr(97))  # 将数字转换成ascii码表对应的字符  # a
#ord
print(ord('a'))  # 将字符按照ascii表转成对应的数字  # 97
# dir获取当前对象名称空间里面的名字
#divmod  用第一个参数除第二个参数,判断余数是否为0,若不为0则商加一.多用在分页
print(divmod(101,10))  # (10, 1)
# enumerate 枚举对迭代对象进行编号,入哦没申明开始序号默认从0开始
l = ['a','b']
for i,j in enumerate(l,1):  # 1 a
    print(i, j)             # 2 b
#  eval 只支持简单的python代码不支持逻辑代码  exec支持逻辑代码
s1 = """
print(1 + 2)
for i in range(3):
    print(i)
"""
# eval(s1)
exec(s1) #3  1  2  3
# format格式化输出
    # 1.{}类似%s占位
    # 2.{}按索引
    # 3.{name}知名道姓
#print(globals())  # 产看全局名称空间
#locals()  # 查看局部名称空间
#help 查看注释
# isinstance 后面统一改方法判断对象是否属于某个数据类型
n = 1
print(type(n))
print(isinstance(n,list))  # 判断对象是否属于某个数据类型 False
print(pow(2,3))  # 前一个数得几次方 8
print(round(3.4))  # 四舍五入 3

  

 

补充面试题:

def func():
    return [lambda x:i*x for i in range(4)]
print([m(2) for m in func()])  # [6,6,6,6]

def func():
    list=[]
    for i in range(4):
        def inner(x):
            return i*x
        list.append(inner)
    return list
print([m(2) for m in func()])  # [6,6,6,6]

def func():
    list=[]
    for i in range(4):
        def inner(x,i=i):
            return i*x
        list.append(inner)
    return list
print([m(2) for m in func()])  # [0,2,4,6]

  

def demo():
    for i in range(4):
        yield i

g=demo()  # g为生成器

g1=(i for i in g)  
g2=(i for i in g1)

print(list(g1))
print(list(g2))

 面向过程:类似于工厂得流水线

  优点:能将复杂得问题流程化,从而将问题简单化

  缺点:程序得拓展性差,一旦某个地方修改,可能全局都需要修改

原文地址:https://www.cnblogs.com/z929chongzi/p/11189601.html