在Python中创建一个列表的常用方法是首先定义一个列表变量,然后依次写出列表中的所有元素。比如,创建一个包含1~5的所有整数的列表:
继续扩展,假设创建一个包含1~10的所有整数的列表,则使用这种方法就不得不将10个整数全部写出来,随着数据量的增大,编程工作量随之骤增。为了减少重复、烦琐的操作,Python引入range()函数,即使用range(1,11)函数表示1~10的所有整数。
再次改变需求,假设创建一个1~10的所有整数平方的列表,则首先想到的是使用for循环来实现,即
在程序中,首先定义了一个空列表list,然后通过for循环遍历1~10的所有整数,将10个整数进行平方运算之后,使用append()函数添加到列表中。
虽然实现了预期的需求,但是需要通过多行代码才能实现,过程非常繁琐。Python以代码量少、简洁、精炼著称。为了实现需求,Python提供了高级特性,即列表推导式。
列表推导式(list comprehensions)是Python内置的非常简单且强大的可以用来轻松创建列表(list)的方法,使用非常简单的语句利用其他列表创建新的列表,使用一行语句即可创建1~10的所有整数平方的列表:
列表推导式的书写规则是,生成的元素放在语句前面,紧跟着的是for循环。
在列表推导式的循环后加上条件判断,可以创建1~10中所有偶数平方的列表。
使用两个for循环即可将两个列表中的元素进行全排列,继而生成新的列表。
运用列表推导式可以快速生成列表,且代码非常简洁。
基于列表继续扩展,如果列表中的元素个数持续扩大,达到10万个,则如此大的列表将占用巨大的内存空间。假设程序实际上只需要访问列表中的几个元素,那么列表占用的绝大多数内存空间都是多余的,纯属浪费。为了解决这个问题,Python引入了 生成器表达式 。
可以通过 生成器表达式 将列表改为一个生成器。列表一旦被创建,所包含的元素就实实在在地存在内存空间了。列表存放的是元素。生成器存放的是算法。由于通过next()调用算法可实时生成元素,因此生成器占用的内存空间很小。
将列表推导式的方括号[]改为小括号(),即可创建一个生成器,即
可以看到,列表list一旦被创建,内存空间就存放了所有元素,生成器g中的元素将随着next()函数的调用实时生成,直到最后没有元素可生成时,抛出StopIteration错误。
除了生成器表达式可以变为生成器,生成器函数同样可以变为生成器,编写一个函数,通过该函数可以计算任意自然数的平方数。
运行结果为
可以看到,square()函数在运行过程中会创建一个列表,若计算的自然数变大,列表也会变大,则程序会占用大量的内存空间,当自然数无限大时,程序将因无法分配到足够的内存空间而无法运行。
为了解决这个问题,借助生成器,将square()函数改为生成器函数,使用 yield关键字 ,即
运行结果为
可以看到,使用生成器函数同样实现了与普通函数同样的功能,区别如下。
生成器代码更简洁。 对比两者的代码,除了用于打印提示信息的代码,生成器的代码量更少,结构更简洁。
生成器占用内存空间极少。 生成器并没有创建列表,更不会因为自然数的变大而消耗大量的内存空间。普通函数则会面临严重的内存空间问题。
运行方式不同。 普通函数是顺序执行的,直到执行完最后一行语句或遇到return语句就返回。生成器函数是遇到yield语句就返回,再次执行时,从返回的地方继续执行。