python基础之迭代器与lamba表达式

迭代

每一次对过程的重复称为一次“迭代”,而每一次迭代得到的结果会作为下一次迭代的初始值。例如:循环获取容器中的元素。

可迭代对象iterable

具有__iter__函数的对象,可以返回迭代器对象。
对list、tuple、dict、set、str等类型的数据可以通过for…in…这类语句迭代读取一条数据供我们使用的对象称之为可迭代对象(Iterable)。

 class 可迭代对象名称:
   def __iter__(self):
       return 迭代器

简单总结:

迭代器 = 可迭代对象.iter()
可以被next()函数调用并返回下一个值的对象

迭代器对象iterator

可以被next()函数调用并返回下一个值的对象。
实现了__next__()魔法方法(类实例化),该方法返回迭代器下一个值(保存得到下一个迭代值的算法)

class 迭代器类名:
	def __init__(self, 聚合对象):
		self.聚合对象= 聚合对象  

	def __next__(self):  
		if 没有元素:
		raise StopIteration
		return 聚合对象元素

理解可迭代对象iterable 与迭代器对象iterator

可迭代对象包含迭代器。
如果一个对象拥有__iter__方法,其是可迭代对象;如果一个对象拥有__next__方法,其是迭代器。
定义可迭代对象,必须实现__iter__方法;定义迭代器,必须实现__iter__和__next__方法。

使用__iter__与__next__实现迭代(不使用for):

# 定义list类型的可迭代对象
my_list = [1, 2, 3, 7, 8, 9]

# 获取迭代器
# iterator = my_list.__iter__() # 直接写法

# iter()函数实际上就是调用了可迭代对象的__iter__方法
iterator = iter(my_list)

# 循环获取下一个元素
while True:
    try:
        # item = iterator.__next__() 直接写法
        item = next(iterator) # 与iter() 同理
        print(item)
    # 异常处理
    except StopIteration:  # 迭代完成
        break

使用函数定义__iter__与__next__实现迭代:

class MyIterator:

    def __init__(self, target):
        self.target = target
      	# 下标计数器
        self.index = 0

    def __next__(self):
    	# 如果 下标计数器 > 可迭代对象长度
        if self.index > len(self.target) - 1:
        	# 报错 
            raise StopIteration()
		
        result = self.target[self.index]
        self.index += 1
        return result

class MyManager:
    """
      可迭代对象
    """

    def __init__(self):
        # 定义一个函数私有变量__list 类型为list
        self.__list = []

    def add_obj(self, obj):
        self.__list.append(obj)

    def __iter__(self):
        # 返回MyIterator类 实例化对象
        return MyIterator(self.__list)


class Test:
    def __str__(self):
        return "这是Test类"


# 实例化MyManager类
manager = MyManager()

manager.add_obj(Test())
manager.add_obj(Test())
manager.add_obj(Test())

iterator = manager.__iter__()
while True:
    try:
        item = iterator.__next__()
        print(item)
    except StopIteration:
        break

生成器generator

能够动态(循环一次计算一次返回一次)提供数据的可迭代对象。

作用:在循环过程中,按照某种算法推算数据,不必创建容器存储完整的结果,从而节省内存空间。数据量越大,优势越明显。在Python中,这种一边循环一边计算的机制,称为生成器:generator

ps: 当数据量足够大时,内存是完全不够用的,但是又需要迭代计算时,需要惰性操作 : 执行一次,计算一次,而不是创建容器,来存储整个对象

生成器函数

含有yield语句的函数,返回值为生成器对象。
yield翻译为”产生”或”生成”
调用生成器函数将返回一个生成器对象,不执行函数体。

# 创建生成器函数
def 函数名A():yield 数据

# 使用生成器函数
for i in 函数名A():
	语句

举例来说:

def Test():
    print('Test1')
    yield 'Test - Test1'
    print('Test2')
    yield 'Test - Test2'
    print('Test3')
    yield 'Test - Test3'

t = Test()
result = next(t)
print(result)

result = next(t)
print(result)

result = next(t)
print(result)

result = next(t) # 第四次调用 超出迭代范围
print(result)
Test1
Test - Test1
Test2
Test - Test2
Test3
Test - Test3
Traceback (most recent call last):
  File "my_test_2.py", line 19, in <module>
    result = next(t)
StopIteration

执行过程:

Setp1 - 调用生成器函数会自动创建迭代器对象。
Setp2 - 调用迭代器对象的__next__()方法时才执行生成器函数。
Setp3 - 每次执行到yield语句时返回数据,暂时离开。
Setp4 - 待下次调用__next__()方法时继续从离开处继续执行。

优点: 不会将所有结果计算出来,存储在内存中
缺点: 无法通过索引,切片灵活的访问结果

  • 延迟操作转为立即操作 list() 函数从而克服缺点

注意:

生成器只可for遍历一次,第二次遍历无效,需要重新调用生成器函数产生生成器

def test(l : list):
    for i in l:
        yield i

if __name__ == '__main__':
    result = test([1, 2, 3])
    for i in result:
        print(i)

    for i in result:
        print(i)

# 结果 只调用一次:
1
2
3

使用 yeild 改写MyManager 实现惰性操作

# class MyIterator:  全部注释掉
# 
#     def __init__(self, target):
#         self.target = target
#         # 下标计数器
#         self.index = 0
# 
#     def __next__(self):
#         # 如果 下标计数器 > 可迭代对象长度
#         if self.index > len(self.target) - 1:
#             # 报错 
#             raise StopIteration()
# 
#         result = self.target[self.index]
#         self.index += 1
#         return result

class MyManager:
    """
      可迭代对象
    """

    def __init__(self):
        # 定义一个函数私有变量__list 类型为list
        self.__list = []

    def add_obj(self, obj):
        self.__list.append(obj)

    def __iter__(self):
        # return MyIterator(self.__list)
        for item in self.__list:
        	# 将函数变为 生成器函数
            yield item

class Test:
    def __str__(self):
        return "这是Test类"


# 实例化MyManager类
manager = MyManager()

manager.add_obj(Test())
manager.add_obj(Test())
manager.add_obj(Test())

iterator = manager.__iter__()
while True:
    try:
        item = iterator.__next__()
        print(item)
    except StopIteration:
        break

lambda表达式

通常是在需要一个函数,但是又不想费神去命名一个函数的场合下使用,也就是指匿名函数。

作用:作为参数传递时语法简洁,优雅,代码可读性强。

定义方法:
变量 = lambda 形参: 方法体

– 形参没有可以不填
– 方法体只能有一条语句,且不支持赋值语句。

# 普通函数
def condition1(item):
    return item // 2

# lambda 匿名函数
num = lambda target: target // 2

if __name__ == '__main__':
    print(condition1(100))  # 50
    print(num(100))  # 50

相对普通方法的优缺点:
优点:

省略方法名
减少程序间依赖性
将方法作为参数,特别优雅

缺点:

由于没有名字,代码不能复用
方法体只能一条语句 错误方法: a = lambda item:print(“ok”) ; item % 2 == 0
方法体必须有返回值

Python之禅中有这么一句话:Explicit is better than implicit(明了胜于晦涩),就是说那种方式更清晰就用哪一种方式,不要盲目的都使用lambda表达式。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章