外贸建站服务,嵌入式网站开发,html购物网站设计,wordpress邮件设置密码前提
一种技术的出现#xff0c;需要考虑#xff1a;
为了实现什么样的需求#xff1b;遇到了什么样的问题#xff1b;采用了什么样的方案#xff1b;最终接近或达到了预期的效果。
概念
提前理解几个概念#xff1a; 迭代 我们经常听到产品迭代、技术迭代、功能迭代…前提
一种技术的出现需要考虑
为了实现什么样的需求遇到了什么样的问题采用了什么样的方案最终接近或达到了预期的效果。
概念
提前理解几个概念 迭代 我们经常听到产品迭代、技术迭代、功能迭代这里的迭代的意思是在现有产品、技术、功能等基础上进行研发升级的过程就可以理解为迭代。 从编程的角度讲迭代是指重复执行一组操作的过程通常是通过循环来实现。在编程中迭代是遍历数据集合的一种方式允许逐个访问集合中的元素。 可迭代 可迭代是指能够被迭代的对象即可以通过迭代遍历其元素的对象。Python中的可迭代对象可以是列表、元组、字典、字符串等。可迭代对象支持使用for循环进行迭代。 可迭代对象 可迭代对象是实现了迭代协议的对象即具有__iter__()方法的对象。该方法返回一个迭代器对象。 迭代器 迭代器是一个具有__iter__()和__next__()方法的对象实现了迭代协议。__iter__()方法返回迭代器对象本身而__next__()方法返回下一个元素。当没有元素可以迭代时__next__()应该引发StopIteration异常。 例如可以使用内置的iter()函数将可迭代对象转换为迭代器。当使用next()函数从迭代器中获取下一个元素时如果没有元素可供迭代将引发StopIteration异常。 生成器 生成器是一种特殊类型的迭代器使用函数来生成值而不是一次性构建并存储在内存中所以极大减少内存使用。 生成器函数使用yield语句产生值而不是return。每次调用生成器的__next__()方法时生成器函数会从上次yield语句的位置恢复执行并继续执行直到遇到下一个yield语句或函数结束。 这样可以有效地处理大量数据因为它们允许逐个生成值而不需要一次性生成整个序列。
普通实现
假设为了实现获取斐波那契数列的前多少位数据一般采用的方式肯定是通过函数计算将函数的计算值一次一次的返回并存储在一个如列表的容器中然后再将容器数据遍历循环处理代码示例如下
def func(p_max):def get_data(a, b):return a ba, b, count 0, 1, 0p_lst []while count p_max:value get_data(a, b)a, b, count b, value, count 1p_lst.append(value)return p_lst
return_values func(1000000000)
print(return_values)
for i in return_values# do somethingpass当p_max不大时p_lst存储的数据不多消耗的内存不大一旦p_max比较大时比如100,000,000时p_lst存储内容就太多了使用的内存也就会变得极大甚至撑爆。 我们可以看一下当p_max设置为100,000,000时30s内存就上限了。 这只是一个方法的使用在开发系统时如果存在这样的操作系统说不定在什么时候就因为内存问题被撑爆了这是很可怕的。
进一步优化
为了避免这样的内存爆炸问题最好的方式就是不存储所有结果计算出一个就消费一个方法每次只返回一个值然后将其他变量覆盖重用循环往复这样不就不会存在内存问题了。
def get_data(a, b):return a b
p_max 1000000000
a, b, count 0, 1, 0
while count p_max:value get_data(a,b)# do something use valueprint(value)经过等待发现内存并没有多少变化说明确实有效果。
但从上面看出这里的循环使用while进行判断操作和我们通常使用的遍历方法用法不同那么是否可以将上述方法采用遍历的形式计算产生并消费呢迭代器
迭代器
首先我们自行创建一个类实现__iter__()和__next__()方法
class MyFb:def __init__(self, a, b, compute_time):# 斐波那契左数self.a a# 斐波那契右数self.b b# 计算多少次几次斐波那契值self.compute_time compute_time# 初始化计次器self.current_time 0def __iter__(self):return selfdef __next__(self):# 当计次器值 小于 总计算次数时计算斐波那契数列值并将a、b向后推移if self.current_time self.compute_time:value self.a self.bself.a self.bself.b valueself.current_time 1#print(%s/%s - %s % (self.current_time,self.compute_time,value))return valueelse:raise StopIteration# 斐波那契起始值0、1共计次10次
myfb MyFb(0, 1, 1000000000)
for i in myfb:# do somethingprint(i)# while myfb:
# try:
# next(myfb)
# except StopIteration as e:
# print(End!)
# break
# 斐波那契起始值0、1共计次10次我们已经可以对通过MyFB类创建的myfb迭代器对象进行逐一遍历获取、访问、处理
但是为了能使对象被遍历需要创建一个类并手动进行内置函数__iter__()和__next__()的定制不仅徒增了代码量也降低了代码的可读性。
有没有什么简单的方法就能实现迭代器的功能还能保持代码易操作、易读的方式 生成器
生成器
生成器Generator实际上是迭代器的一种特殊类型。生成器只是一种便捷实现迭代器的方式而已
通过使用函数和 yield 语句创建迭代器每次执行完后会将global(), local() 环境变量缓存起来下次执行时从yield处开始并恢复global(), local() 环境变量每次遍历时执行到yield时就将 yield后的结果返回回来生成器函数并不使用return。
生成器具有迭代器的所有特性并且还有一些额外的优势。
为了明显的说明其原理我们写一个比较简单理解但是并不美观的代码
def fun(p_max):a 0b 1count 0while count p_max:value a byield valuea bb valuecount 1g_values fun(100000000)
print(g_values)
while True:try:p_value next(g_values)print(p_value)except StopIteration:print(END!)break因为for兼容了迭代器的异常处理所以我们可以直接使用
def fun(p_max):a 0b 1count 0while count p_max:value a byield valuea bb valuecount 1g_values fun(10000000000)
print(g_values)
for i in g_values:print(i)继续简化代码可以写为
def fun(p_max):a,b,count 0,1,0while count p_max:yield aba,b,count b,ab,count1for i in fun(10000000000):print(i)所以迭代器是一种访问数据的方式生成器是一种更加便捷实现的形式而它们最主要的优点就是延迟数据生成减少内存消耗不要将其想的太复杂只是一种措施、一种手段而已。
优缺点
生成器原本即为迭代器的特殊模式所以可以看一下对于迭代器而言的优缺点都有哪些。
优点
内存效率 迭代器按需生成元素一次只产生一个元素因此在处理大规模数据集时迭代器能够更好地节省内存。这对于在有限内存环境中处理大型数据集或流式数据非常有利。惰性计算 迭代器支持惰性计算只在需要时生成元素。这使得它们适用于处理无限序列或大规模数据因为不需要一次性生成整个序列。适用于多次迭代 一旦迭代器耗尽了所有元素可以通过重新调用 __iter__() 方法将其重新初始化使得可以再次从头开始迭代。这使得迭代器适用于需要多次迭代相同数据集的情况。支持 for 循环 迭代器实现了迭代协议因此可以直接用于 for 循环中。这样的代码更加简洁和易读。支持无限序列 由于迭代器是按需生成元素的它们可以用于表示无限序列。这在模拟无限数据流等场景中非常有用。支持并发操作 由于迭代器是逐个产生元素的它们可以在多线程或多进程环境中更容易地被共享和处理而不需要担心整个数据集的同步问题。
缺点
不支持随机访问 迭代器一次只能产生一个元素无法通过索引直接访问元素。如果需要通过索引或其他方式随机访问数据集的元素迭代器可能不是最佳选择。代码繁琐 相对于直接使用列表等数据结构实现迭代器可能需要编写更多的代码包括实现 __iter__() 和 __next__() 方法。这可能在某些情况下增加了代码的复杂性。不适用于所有场景 尽管迭代器在许多情况下非常有用但并不是所有问题都适合使用迭代器。在某些场景下传统的数据结构和方法可能更加直观和简单。一次性消耗 大多数迭代器是一次性的即一旦迭代器耗尽了所有元素就不能重新开始。这与一些需要多次迭代相同的场景不匹配。不易调试 由于迭代器是按需生成元素的当程序发生错误时调试可能变得更加困难。在某些情况下你可能无法直接查看整个数据集而需要通过逐步迭代来定位问题。不支持修改 大多数迭代器是只读的不支持在迭代过程中修改数据集。如果需要修改数据集可能需要使用其他数据结构。 如果对你有所帮助可以点赞、关注、收藏起来不然下次就找不到了 【点赞】⭐️⭐️⭐️⭐️⭐️ 【关注】⭐️⭐️⭐️⭐️⭐️ 【收藏】⭐️⭐️⭐️⭐️⭐️
Thanks for watching. –Kenny