你知道以下语法之间的区别吗?
[x for x in range(5)]
(x for x in range(5))
tuple(range(5))
本文将向您介绍这里的区别。
首先,对列表进行简短回顾(在其他编程语言中通常称为“数组”):
列表是一种可以表示为元素集合的数据。一个简单的列表如下所示:[0, 1, 2, 3, 4, 5] 列表将所有可能类型的数据和数据组合作为其元素:
>>> a = 12
>>> b = "this is text"
>>> my_list = [0, b, ['element', 'another element'], (1, 2, 3), a]
>>> print(my_list)
[0, 'this is text', ['element', 'another element'], (1, 2, 3), 12]
列表可以编入索引。您可以使用以下语法访问任何单个元素或元素组:
>>> a = ['red', 'green', 'blue']
>>> print(a[0])
red
与字符串不同,列表在Python中是可变的。这意味着您可以替换,添加或删除元素。 您可以使用for循环和range()函数创建列表。
>>> my_list = []
>>> for x in range(10):
... my_list.append(x * 2)
...
>>> print(my_list)
[0, 2, 4, 6, 8, 10, 12, 14, 16, 18]
通常被视为Python中函数式编程的一部分,列表推导允许您使用包含较少代码的for循环创建列表。
使用列表推导来查看前一个示例的实现:
>>> comp_list = [x * 2 for x in range(10)]
>>> print(comp_list)
[0, 2, 4, 6, 8, 10, 12, 14, 16, 18]
上面的示例过于简单,可以让您了解语法。使用更简单的list(range(0, 19, 2))功能可以实现相同的结果。
您还可以在推导的第一部分中使用更复杂的修改器,或添加将过滤列表的条件。像这样的东西:
>>> comp_list = [x ** 2 for x in range(7) if x % 2 == 0]
>>> print(comp_list)
[4, 16, 36]
另一个可用选项是使用列表推导来组合多个列表并创建列表列表。乍一看,语法似乎很复杂。将列表视为外部序列和内部序列可能会有所帮助。
当您想要通过组合两个现有列表来创建列表列表时,是时候展示列表推导的强大功能了:
>>> nums = [1, 2, 3, 4, 5]
>>> letters = ['A', 'B', 'C', 'D', 'E']
>>> nums_letters = [[n, l] for n in nums for l in letters]
#the comprehensions list combines two simple lists in a complex list of lists.
>>> print(nums_letters)
>>> print(nums_letters)
[[1, 'A'], [1, 'B'], [1, 'C'], [1, 'D'], [1, 'E'], [2, 'A'], [2, 'B'], [2, 'C'], [2, 'D'], [2, 'E'], [3, 'A'], [3, 'B'], [3, 'C'], [3, 'D'], [3, 'E'], [4, 'A'], [4, 'B'], [4, 'C'], [4, 'D'], [4, 'E'], [5, 'A'], [5, 'B'], [5, 'C'], [5, 'D'], [5, 'E']]
>>>
让我们用文本尝试它,或者说字符串对象是正确的。
>>> iter_string = "some text"
>>> comp_list = [x for x in iter_string if x !=" "]
>>> print(comp_list)
['s', 'o', 'm', 'e', 't', 'e', 'x', 't']
推导不仅限于列表。您也可以创建dicts并设置推导。
>>> dict_comp = {x:chr(65+x) for x in range(1, 11)}
>>> type(dict_comp)
<class 'dict'>
>>> print(dict_comp)
{1: 'B', 2: 'C', 3: 'D', 4: 'E', 5: 'F', 6: 'G', 7: 'H', 8: 'I', 9: 'J', 10: 'K'}
>>> set_comp = {x ** 3 for x in range(10) if x % 2 == 0}
>>> type(set_comp)
<class 'set'>
>>> print(set_comp)
{0, 8, 64, 512, 216}
如果你了解了迭代和迭代器,那么理解生成器的概念会更容易。
Iterable是数据的“序列”,您可以使用循环迭代。可迭代的最简单可见示例可以是整数列表 - [1, 2, 3, 4, 5, 6, 7]。可以迭代其他类型的数据,如字符串,dicts,元组,集合等。
基本上,任何具有iter()方法的对象都可以用作可迭代的。您可以使用hasattr()解释器中的函数进行检查。
>>> hasattr(str, '__iter__')
True
>>> hasattr(bool, '__iter__')
False
迭代一系列数据时,就会实现迭代器协议。例如,当您使用for循环时,后台发生以下情况:
iter()在对象上调用第一个方法将其转换为迭代器对象。 在迭代器对象上调用该方法以获取序列的下一个元素。 next() 如果StopIteration没有要调用的元素,则会引发异常。
>>> simple_list = [1, 2, 3]
>>> my_iterator = iter(simple_list)
>>> print(my_iterator)
<list_iterator object at 0x7f66b6288630>
>>> next(my_iterator)
1
>>> next(my_iterator)
2
>>> next(my_iterator)
3
>>> next(my_iterator)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
StopIteration
在Python中,生成器提供了一种实现迭代器协议的便捷方式。Generator是一个使用带有yield语句的函数创建的迭代。
生成器的主要特征是按需评估元素。当您使用return语句调用普通函数时,只要遇到return语句,函数就会终止。
在带有yield语句的函数中,函数的状态从上次调用中“保存”,并且可以在下次调用生成函数时被拾取
>>> def my_gen():
... for x in range(5):
... yield x
生成器表达式允许在没有yield关键字的情况下即时创建生成器。但是它们不能分享用yield函数创建的生成器的全部功能。
语法和概念类似于列表推导的语法和概念:
>>> gen_exp = (x ** 2 for x in range(10) if x % 2 == 0)
>>> for x in gen_exp:
... print(x)
0
4
16
36
64
在语法方面,唯一的区别是你使用括号而不是方括号。
列表推导和生成器表达式返回的数据类型不同。
>>> list_comp = [x ** 2 for x in range(10) if x % 2 == 0]
>>> gen_exp = (x ** 2 for x in range(10) if x % 2 == 0)
>>> print(list_comp)
[0, 4, 16, 36, 64]
>>> print(gen_exp)
<generator object <genexpr> at 0x7f600131c410>
生成器在列表中的主要优点是它占用的内存要少得多。我们可以使用sys.getsizeof()方法检查两种类型占用的内存量。
注意:在Python 2中,使用range()函数实际上无法反映大小方面的优势,因为它仍然将整个元素列表保存在内存中。但是,在Python 3中,这个例子是可行的,因为它range()返回一个范围对象。
>>> from sys import getsizeof
>>> my_comp = [x * 5 for x in range(1000)]
>>> my_gen = (x * 5 for x in range(1000))
>>> getsizeof(my_comp)
9024
>>> getsizeof(my_gen)
88
生成器一次生成一个项目 - 因此它比列表更有内存效率。
例如,当您想迭代列表时,Python会为整个列表保留内存。生成器不会将整个序列保留在内存中,并且只会根据需要“生成”序列的下一个元素。
可能会吓到或劝阻新手程序员的第一件事就是教育材料的规模。这里的诀窍是将每个概念视为语言提供的选项,您不应该同时学习所有语言概念和模块。
总有不同的方法来解决同一个任务。把它作为完成工作的另一个工具。
查看英文原文:https://djangostars.com/blog/list-comprehensions-and-generator-expressions/
查看更多文章:www.apexyun.com
公众号:银河系1号
联系邮箱:public@space-explore.com
(未经同意,请勿转载)