Tristahong 2020-08-05
在本教程中,我们将展示11个技巧来编写更好的Python代码!我们展示了许多优秀实践,它们通过使代码更加简洁和更具python风格来改进代码。以下是所有技巧的概述:
1. 使用enumerate()而不是range(len())进行迭代
如果我们需要遍历一个列表,并且需要跟踪索引和当前项,大多数人会使用range(len())语法。在本例中,我们希望遍历一个列表,检查当前项是否为负,并在本例中将列表中的值设置为0。虽然range(len())语法可以工作,但使用内置的枚举函数更好。这将以元组的形式返回当前索引和当前项。因此,我们可以直接检查这里的值,也可以访问带有索引的项。
data = [1, 2, -3, -4] # weak: for i in range(len(data)): if data[i] < 0: data[i] = 0 # better: data = [1, 2, -3, -4] for idx, num in enumerate(data): if num < 0: data[idx] = 0
2. 使用list comprehension代替原始的for循环
假设我们想要创建一个具有特定值的列表,在本例中是一个包含0到9之间所有平方数的列表。冗长乏味的方法是创建一个空列表,然后使用for循环,进行计算,并将其附加到列表中:
squares = [] for i in range(10): squares.append(i*i)
一种更简单的方法是list comprehension。这里我们只需要一行来实现同样的事情:
# better: squares = [i*i for i in range(10)]
list comprehension能力非常强大,甚至包括if语句。注意,list comprehension的用法有一点争议。它不应该被过度使用,尤其是当它损害了代码的可读性时。但我个人认为这种语法是清晰和简洁的。
3. 使用内置的Sort()方法对复杂的迭代进行排序
如果我们需要对一些可迭代的对象,例如列表、元组或字典进行排序,我们不需要自己实现排序算法。我们可以简单地使用内置的排序函数。这将自动按升序对数字进行排序,并返回一个新的列表。如果我们想让结果按降序排列,我们可以使用参数reverse=True。正如我所说的,这适用于任何可迭代的对象,所以这里我们还可以使用元组。但是请注意,结果是一个列表!
data = (3, 5, 1, 10, 9) sortedsorted_data = sorted(data, reverse=True) # [10, 9, 5, 3, 1]
现在假设我们有一个复杂的迭代器。这里是一个列表,列表里面有字典,我们想要根据字典中的年龄对列表进行排序。为此,我们还可以使用排序函数,然后传入应该用于排序的关键参数。键必须是一个函数,所以这里我们可以使用lambda和返回年龄的单行函数。
data = [{"name": "Max", "age": 6}, {"name": "Lisa", "age": 20}, {"name": "Ben", "age": 9} ] sortedsorted_data = sorted(data, key=lambda x: x["age"])
4. 用集合存储惟一的值
如果我们有一个有多个值的列表,并且只需要唯一的值,一个很好的技巧是将我们的列表转换为集合。集合是一种无序的集合数据类型,没有重复的元素,所以在这种情况下,它删除了所有重复的元素。
my_list = [1,2,3,4,5,6,7,7,7] my_set = set(my_list) # removes duplicates
如果我们已经知道我们需要唯一的元素,比如这里的质数,我们可以马上用花括号创建一个集合。这允许Python进行一些内部优化,并且它还有一些方便的方法来计算两个集合之间的交集和差异。
5. generator节省内存
在技巧2中,我向你展示了list comprehension。但是列表并不总是最好的选择。假设我们有一个非常大的列表有10000项我们想计算所有项的和。当然,我们可以使用列表来实现这一点,但是我们可能会遇到内存问题。这是一个我们可以使用生成器的完美例子。与list comprehension类似,我们可以使用生成器理解,它具有相同的语法,但使用圆括号而不是方括号。生成器懒洋洋地计算我们的元素,即。,它一次只生成一个条目,并且只在被请求时生成。如果我们计算这个生成器的和,我们看到我们得到了相同的正确结果。
# list comprehension my_list = [i for i in range(10000)] print(sum(my_list)) # 49995000 # generator comprehension my_gen = (i for i in range(10000)) print(sum(my_gen)) # 49995000
6. 用.get()和.setdefault()在字典中定义默认值
假设我们有一个字典,它有不同的键,比如物品和物品的价格。在代码的某个时候,我们想要获得条目的计数,并且假设这个键也包含在字典中。当我们简单地尝试访问密钥时,它将崩溃我们的代码并引发一个KeyError。所以更好的方法是在字典上使用.get()方法。这也会返回键的值,但是如果键不可用,它不会引发键错误。相反,它返回我们指定的默认值,如果我们没有指定它,则返回None。
my_dict = {'item': 'football', 'price': 10.00} price = my_dict['count'] # KeyError! # better: price = my_dict.get('count', 0) # optional default value
7. 用collections.Counter计数hashable对象
如果我们需要计算列表中元素的数量,那么在collections模块中有一个非常方便的工具可以完成此工作。我们只需要从集合中导入计数器,然后用列表作为参数创建计数器对象。如果我们打印这个,那么对于列表中的每一项,我们都可以看到这个项出现的次数,而且它已经排好序了,最常用的项在前面。单独计算会好得多。如果我们想要获得某一项的计数,只需访问该项,它就会返回相应的计数。如果不包含该项,则返回0。
from collections import Counter my_list = [10, 10, 10, 5, 5, 2, 9, 9, 9, 9, 9, 9] counter = Counter(my_list) print(counter) # Counter({9: 6, 10: 3, 5: 2, 2: 1}) print(counter[10]) # 3
8. 用f-strings格式化字符串(Python 3.6+)
这是自Python 3.6以来的新特性,在我看来是格式化字符串的最佳方式。我们只需要在字符串前面写一个f,然后在字符串里面我们可以使用大括号来访问变量。与旧的格式化规则相比,这更简单、更简洁,也更快。此外,我们可以在大括号中编写在运行时计算的表达式。举个例子,我们想要输出变量i的平方,我们可以简单地把这个操作写在f字符串中。
name = "Alex" my_string = f"Hello {name}" print(my_string) # Hello Alex i = 10 print(f"{i} squared is {i*i}") # 10 squared is 100
9. 用.join()连接字符串
假设我们有一个包含不同字符串的列表,我们想将所有元素组合成一个字符串,每个单词之间用空格分隔。坏的方法是这样做:
list_of_strings = ["Hello", "my", "friend"] # BAD: my_string = "" for i in list_of_strings: my_string += i + " "
我们定义了一个空字符串,然后遍历该列表,然后将单词和空格追加到该字符串。你应该知道,字符串是不可变的元素,所以这里我们每次都要创建新的字符串。对于大型列表,此代码可能非常慢,所以您应该立即忘记这种方法!更好、更快、也更简洁的是.join()方法:
.join() method: # GOOD: list_of_strings = ["Hello", "my", "friend"] my_string = " ".join(list_of_strings)
10. 用双星号语法合并字典** (Python 3.5+)
这种语法是自Python 3.5以来的新语法。如果我们有两个字典并且想要合并它们,我们可以为两个字典使用花括号和双星号。这里字典1有名字和年龄,字典2也有名字和城市。在与这个简洁的语法合并之后,我们最终的字典中有所有3个键。
d1 = {'name': 'Alex', 'age': 25} d2 = {'name': 'Alex', 'city': 'New York'} merged_dict = {**d1, **d2} print(merged_dict) # {'name': 'Alex', 'age': 25, 'city': 'New York'}
11. 用if x in list简化if语句,而不是单独检查每一项
假设我们有一个主色为红色、绿色和蓝色的列表。在代码的某个地方,我们有一个包含一些颜色的新变量,这里是c =红色。然后我们要检查这个颜色是否来自我们的主色。我们当然可以像这样检查列表中的每一项: