作者|Philip Wilkinson
编译|VK
来源|Towards Datas Science
在使用Python将近一年的时间里,我经常遇到“生成式”这个词,但我没生成式它的确切含义或它所涵盖的内容。
直到最近,我才发现,有了生成式后,我可以利用列表将我的代码从多行缩短为一行。此外,这种代码缩短方法不仅可以用于列表,还可以用于字典和集合。
本文试图解释生成式在列表、字典和集合的适用性,以及它们如何减少日常编程所需的代码量。
首先,生成式是可以在一行中创建列表、字典和集合的代码片段。这样就不必为for循环使用多行,而且还减少了使用map()、filter()和reduce()函数的需要。
它们由方括号(根据你要创建的数据类型而定)组成,其中包含一个表达式,后跟一个for子句和一个或多个if子句。表达式本身可以是任何东西,这意味着你可以将许多不同的对象放入列表中,只要它们是可编辑的。因此,从减少使用的行数和增加可读性的角度来探讨这些可能对代码产生的影响是值得的。
列表
在python中,只需将项目放在方括号([])内,用逗号分隔,就可以创建列表,如下所示。
list1 = [1, 2, 3, "hello", 7.0, 52]
它们通常用于多种目的的编程中,但在长格式中编写或使用for循环进行编辑都会很麻烦。首先,在创建列表方面,小列表可能很容易以长格式打印出来,例如:
nums = [1, 2, 3, 4, 5, 6, 7, 8]
但当这个值变长时,即在0-50范围内,甚至更长,它们可能会变得笨重。它们可以通过for循环使用range函数轻松创建,如下所示:
nums = []
for i in range(1, 51):
nums.append(i)
print(nums)
# out: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50]
但是我们可以使用列表生成式将其缩短为一行,并且不需要append()方法。
nums = [i for i in range(1,51)]
print(nums)
# out: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50]
基本上,for循环放在一行中,同时初始化列表,从上面的示例中消除了对第一行和第二行代码的需要。
当我们开始为添加到列表中的数字添加条件时,这就变得更加重要了,比如只允许偶数并且希望这些数字是平方的。同样,也可以使用for循环生成,如下所示:
square_nums = []
for x in range(1,26):
if x % 2 == 0:
square_nums.append(x**2)
print(square_nums)
# out: [4, 16, 36, 64, 100, 144, 196, 256, 324, 400, 484, 576]
但是,同样可以使用列表生成式将其缩短为一行,从而减少对用于在范围内循环、创建条件并将结果附加到原始列表的行的需要。
square_nums = [x**2 for x in range(1,26) if x % 2 == 0]
print(square_nums)
#out: [4, 16, 36, 64, 100, 144, 196, 256, 324, 400, 484, 576]
在这里,数字的转换在行首执行x**2,for循环在行中执行,对于x在范围(1,26),条件在末尾执行,就好像x%2==0一样。这本质上使代码更具可读性,因为所有操作都在一行中执行,并减少了生成相同输出所需的代码量。
这还可以减少append()、map()、filter()或reduce()方法在创建新列表时对现有列表进行操作的需要,再次降低代码的复杂性并使其更具可读性。
类似的例子是很容易获得的,更多的信息可以很容易地通过其他文章在媒介,如这里和这里获得。然而,值得注意的是,这些生成式也可以用于字典和集合。
字典
字典是一个无序的数据集合,可以改变和索引,使用大括号和键和值对编写。在这里,键被用来访问值,并且经常被用来存储信息,这些信息对这些信息是有用的。下面提供了一个示例,例如用于存储分数。
Grades = {
"Steven": 57,
"Jessica": 82,
"William": 42,
"Hussein": 78,
"Mary": 65,
}
print(Grades)
# out: {'Steven': 57, 'Jessica': 82, 'William': 42, 'Hussein': 78, 'Mary': 65}
与列表类似,有时也会很耗时,因此可以使用for循环和条件语句来构造,但可以更简单地使用生成式来构造。
例如,对于我们在上面创建的列表,我们不仅想知道数字的平方,而且还想存储原始数字,这样我们就可以使用它轻松地查找它的平方值。然后,我们可以简单地创建一个包含键值对的字典,其中key代表原始数字,value代表数字的平方。使用for循环:
#初始化空dict
even_squared_dict = {}
for x in range(1,10):
if x % 2 == 0:
even_squared_dict[x] = x**2
print(even_squared_dict)
# out: {2: 4, 4: 16, 6: 36, 8: 64}
但是使用字典生成式:
even_sqaured_dict = {x: x**2 for x in range(1,10) if x % 2 ==0}
print(even_squared_dict)
# out: {2: 4, 4: 16, 6: 36, 8: 64}
本质上,这个和列表生成式之间的唯一区别是使用大括号来包含生成式,并将x放在冒号前面,以指示这表示键。
然后,还可以使用它来创建基于现有列表的字典。例如下面,字典生成式用于创建一个字典,其键为三位数的国家代码,值为两位数的国家代码,其中两位数代码与三位数代码的前两位数相同。
ThreeCharCodes = ["CAN", "FIN", "FRA", "GAB", "HKG", "IMN",
"MCO", "NPL"]
cntryDict = {c: c[:2] for c in threeCharCodes}
print(cntryDict)
# out: {'CAN': 'CA', 'FIN': 'FI', 'FRA': 'FR', 'GAB': 'GA', 'HKG': 'HK', 'IMN': 'IM', 'MCO': 'MC', 'NPL': 'NP'}
集合
最后,生成式也可以用于创建集合,集合是一种不同于列表或元组的数据类型,不能存储同一元素的多次出现。
在这样做时,它存储无序值,初始化方法是将一个列表传递给set()或使用大括号来包含由逗号分隔的值(尽管空的花括号将初始化字典)。下面提供了一个例子:
Fruits1 = set(["apple", "banana", "cherry", "apple"])
print(Fruits1)
Fruits2 = {"orange", "pear", "grape", "pear"}
print(Fruits2)
# out: {'apple', 'cherry', 'banana'}
{'grape', 'pear', 'orange'}
从这里可以清楚地看到,尽管向集合传递了多个apple或pear值,但只生成了一个实例。同样,可以使用for循环生成这些命令,如下所示:
import random
nums = set([])
for x in range(25):
y = random.randint(10,20)
nums.add(y)
print(nums)
# out: {10, 12, 14, 15, 16, 17, 18, 20}
虽然25个随机整数在10-20之间,但最终输出仅包含8个唯一值,而不是列表中出现的25个值。同样,使用对集合的生成式可以更简洁地编写这篇文章。
nums = {random.randint(10,20) for num in range(25)}
print(nums)
# out: {11, 12, 13, 14, 15, 16, 17, 19, 20}
因此,这种生成式与列表生成式的区别在于使用大括号,而不是包含生成式的方括号。
与列表和字典生成式类似,这也可以用于现有列表以生成集合。例如,如果我们想根据1.6的除法将公里改为英里,只需要唯一的值,并将其限制为小于100公里的值。
kms = [10, 12, 65, 40, 12, 75, 34, 65, 10, 10, 38, 100, 160, 200]
miles = {d/1.6 for d in kms if d < 100}
print(miles)
# out: {0.625, 0.75, 2.5, 2.125, 4.0625, 4.6875, 2.375}
总结
因此,生成式可以很容易地用于创建新的列表、词典和集合。使用这些可以减少生成它们所需的行数,并提高可读性。它们可以用作append()、map()、filter()或reduce()函数的替换。
显然,可以将它们放大以执行更复杂的生成式,例如使用lambda函数、嵌套列表生成式或多条件语句。然而,在这样做时值得注意的是,生成式可能很快变得难以理解,在这种情况下,值得回到创建函数或for循环,以便在需要执行多个操作时提高可读性。
欢迎关注磐创AI博客站:
http://panchuang.net/
sklearn机器学习中文官方文档:
http://sklearn123.com/
欢迎关注磐创博客资源汇总站:
http://docs.panchuang.net/
原创文章,作者:磐石,如若转载,请注明出处:https://panchuang.net/2020/10/19/%e4%bd%bf%e7%94%a8%e5%88%97%e8%a1%a8%e3%80%81%e5%ad%97%e5%85%b8%e5%92%8c%e9%9b%86%e5%90%88%e7%94%9f%e6%88%90%e5%bc%8f%e6%9d%a5%e7%bc%a9%e7%9f%ad%e4%bb%a3%e7%a0%81/