python之迭代器,生成器以及列表推导式

 

可迭代对象

  对象内部含有 __iter__方法就是可迭代对象。

    可迭代对象:str list dict tuple set range()

  可迭代对象满足可迭代协议

判断一个对象是否可迭代:

  第一个方法:

print('__iter__ in dir(s))

  第二个方法:

from collections import Iterable  # 判断可迭代对象
from  collections import Iterator   # 判断迭代器

print(isinstance('alex', Iterable))  # 判断类型

 

迭代器:

  对象内部含有__iter__方法,且含有__next__方法就是迭代器。

判断一个对象是否迭代器:

 print('__next__' in dir(f))

  

# 可迭代对象
# for i in 'abc':
# #     print(i)

# 对象内部含有 __iter__ 方法就是可迭代对象。
# s = '123'
# print(dir(s))

# 判断一个对象是否可迭代对象:
# 第一种方法
# print('__iter__' in dir(s))

# 第二种方法
from collections import Iterable  # 判断可迭代对象
from  collections import Iterator   # 判断迭代器

print(isinstance('alex', Iterable))  # 判断类型



# 迭代器
# 判断一个对象是否可迭代器
f = open('a', encoding='utf-8', mode='w')
print('__next__' in dir(f))

  

可迭代对象 vs 迭代器

  • 1. 可迭代对象不能取值,迭代器是可以取值的。
  • 可迭代对象 --->(转化成) 迭代器:
  • 2. 迭代器非常节省内存。
  • 只加载一个内存地址,next一下,加载这个内存的地址+
  • 3. 迭代器每次只会取一个值。
  • 4. 迭代器单向的,不反复,一条路走到头。会记录地址


数据量很大 只是取值 用迭代器。




while循环 模拟 for 循环内部机制:

  • 1. 将可迭代对象转化成迭代器。
  • 2. 调用__next__ 方法取值
  • 3. 利用异常处理停止报错
# 可迭代对象 --->(转化成) 迭代器:
lis = [1, 2, 3] # 可迭代对象
ite1 = lis.__iter__()  # 迭代器
print(ite1)

# 迭代器如何取值  next一次,取一个值
print(ite1.__next__())  # 写一步 取一个


# while循环 模拟 for 循环:
# 1. 将可迭代对象转化成迭代器。
# 2. 调用__next__ 方法取值
# 3. 利用异常处理停止报错


s = 'sdgs'
iter2 = s.__iter__()
while 1:
    try:
        print(iter2.__next__())
    except StopIteration:
        break

  

生成器

生成器:就是自己python用代码写的迭代器,生成器的本质就是迭代器。

用一下两种方式构建一个生成器:

  • 通过生成器函数
  • 生成器表达式
def func2(x):
    x += 1
    print(111)
    yield x
    print(222)
g_obj = func2(5)   # 生成器函数对象
# print(g_obj)  <generator object func2 at 0x000001933AEB9408>
# g_obj.__next__()  #111
# g_obj.__next__()  #222
# 一个next对应一个yield
# yield 将值返回给 生成器对象.__next__()

yield return 区别

  • return结束函数,给函数的执行者返回值
  • yield 不会结束函数,一个next对应一个yield,给 生成器对象.__next__() 返回值

生成器函数 迭代器

  • 区别区别1:自定制区别
  • 区别2:内存级别的区别 迭代器需要可迭代对象进行转化。

       可迭代对象是非常占内存的 生成器是直接创建,不需要转化。从本质上就节省内存。

  

区别1 自定制去呗

# l1 = [1, 2, 3, 4, 5]
# l1.__iter__()


# def func1(x):
#     x += 1
#     yield x
#     x += 3
#     yield x
#     x += 5
#     yield x
#
#
# g1 = func1(5)
# print(g1.__next__())
# print(g1.__next__())
# print(g1.__next__())



# 区别2 内存级别区别
# def func3():
#     for i in range(100000):
#         yield i
# g2 = func3()
# for i in range(50):
#     print(g2.__next__())
def func(x):
    x += 1
    yield x
    x += 2
    yield x

# 得到两个生成器对象
# print(func(8).__next__())  # 9
# print(func(8).__next__())   # 9


# 得到一个生成器对象
g = func(8)
print(g.__next__())  # 9
print(g.__next__())  # 11
生成器的赋值

send 与 next 区别  

  • send 与 next 一样,也是对生成器取值(执行一个yield)的方法
  • send 可以给 上一个yield传值。
  • 第一次取值永远都是next
  • 最后一个yield永远也得不到send传的值
# send 与 next
def func1():
    # print(1)
    count = yield 6
    print(count)
    # print(2)
    yield 7
    # print(3)
    yield 8


g1 = func1()
# next(g1)
print(next(g1))
g1.send('alex')
next(g1)

  

列表推导式:一行代码几乎搞定你需要的任何列表

  • 循环模式 [变量(加工后的变量) for 变量 in iterable]

  • 筛选模式 [变量(加工后的变量) for 变量 in iterable if 条件]

l = [i for i in range(1,101)]
print(l)


l = ['python %s 期' % i for i in range(1, 16)]
print(l)

l = [i**2 for i in range(1, 11)]
print(l)
循环模式
l = [i for i in range(1, 31) if i % 2 == 0]
print(l)

l = [i for i in range(1, 31) if i % 3 == 0]
print(l)

l = [i**2 for i in range(1, 31) if i % 3 == 0]
print(l)

names = [['Tom', 'Billy', 'Jefferson', 'Andrew', 'Wesley', 'Steven', 'Joe'],
         ['Alice', 'Jill', 'Ana', 'Wendy', 'Jennifer', 'Sherry', 'Eva']]
l = [j for i in names for j in i if j.count('e') == 2]
print(l)
筛选模式

列表推导式:
优点:一行解决,方便。
缺点:容易着迷,不易排错,不能超过三次循环
列表推导式不能解决所有列表的问题,所以平时的代码不要太刻意用。

# 生成器表达式: 将列表推导式的 [] 换成 () 即可
g = (i for i in range(100))
print(g.__next__())
print(next(g))

#

  

原文地址:https://www.cnblogs.com/eaoo/p/9494142.html