你知道如下语法之间的区别吗?程序员
[x for x in range(5)]
(x for x in range(5))
tuple(range(5))
复制代码
本文将向您介绍这里的区别。express
首先,对列表进行简短回顾(在其余编程语言中一般称为“数组”):django
列表是一种能够表示为元素集合的数据。一个简单的列表以下所示:[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()函数建立列表。bash
>>> 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循环建立列表。app
使用列表推导来查看前一个示例的实现:编程语言
>>> 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会为整个列表保留内存。生成器不会将整个序列保留在内存中,而且只会根据须要“生成”序列的下一个元素。
可能会吓到或劝阻新手程序员的第一件事就是教育材料的规模。这里的诀窍是将每一个概念视为语言提供的选项,您不该该同时学习全部语言概念和模块。
总有不一样的方法来解决同一个任务。把它做为完成工做的另外一个工具。
查看更多文章:www.apexyun.com
公众号:银河系1号
联系邮箱:public@space-explore.com
(未经赞成,请勿转载)