如何编写高效的Python代码:初学者教程
编写高效Python代码的终极指南:初学者教程
初学者程序员喜欢用Python编写代码,因为它简单易读。然而,编写高效的Python代码比你想象的更复杂。它需要理解一些语言的特点(尽管它们同样简单)。
如果您来自C ++或JavaScript等其他编程语言,这个教程适合您学习一些编写高效Python代码的技巧。但如果您是初学者 – 将Python作为第一(编程)语言学习,那么本教程将帮助您从一开始就编写Pythonic的代码。
我们将关注以下内容:
- Pythonic循环
- 列表和字典推导式
- 上下文管理器
- 生成器
- 集合类
所以让我们开始吧!
1.编写Pythonic循环
无论您使用哪种语言编程,理解循环结构都很重要。如果您来自C ++或JavaScript等语言,学习如何编写Pythonic循环是很有帮助的。
使用range生成数列
range()函数生成一个序列,通常用作循环中的迭代器。
range()函数返回一个范围对象,默认从0开始,到指定的数字(但不包括该数字)。
这是一个示例:
for i in range(5): print(i)
输入>> > 01234
使用range()函数时,可以根据需要自定义起始点、结束点和步长。
使用enumerate同时访问索引和元素
当您希望同时获得可迭代对象中每个元素的索引和值时,enumerate()函数非常有用。
在这个例子中,我们使用索引来访问水果列表:
fruits = ["apple", "banana", "cherry"] for i in range(len(fruits)): print(f"Index {i}: {fruits[i]}")
输出>> > 索引0:苹果索引1:香蕉索引2:樱桃
但是使用enumerate()函数,您可以这样访问索引和元素:
fruits = ["apple", "banana", "cherry"] for i, fruit in enumerate(fruits): print(f"Index {i}: {fruit}")
输出>> >索引0:苹果索引1:香蕉索引2:樱桃
使用zip在多个可迭代对象上并行迭代
zip()函数用于同时迭代多个可迭代对象。它将来自不同可迭代对象的相应元素进行配对。
考虑以下示例,您需要循环遍历names和scores列表:
names = ["Alice", "Bob", "Charlie"] scores = [95, 89, 78] for i in range(len(names)): print(f"{names[i]}得分是{scores[i]}分。")
这将输出:
输出>> >爱丽丝得分95分。鲍勃得分89分。查理得分78分。
这是一个更易读的循环例子,使用了 zip()
函数:
names = ["Alice", "Bob", "Charlie"]
scores = [95, 89, 78]
for name, score in zip(names, scores):
print(f"{name} 得了 {score} 分.")
输出结果 >>> Alice 得了 95 分.Bob 得了 89 分.Charlie 得了 78 分.
使用 zip()
来写的 Pythonic 版本更加简洁,避免了手动索引的需要-让代码更干净、更易读。
2. 使用列表和字典解析
在 Python 中,列表解析和字典解析是创建列表和字典的简洁的一行代码。它们还可以包含条件语句以根据特定条件过滤项目。
我们从循环版本开始,然后转向列表和字典的解析表达式。
Python 中的列表解析
假设你有一个 numbers
列表。你想创建一个 squared_numbers
列表。你可以使用以下的循环代码:
numbers = [1, 2, 3, 4, 5]
squared_numbers = []
for num in numbers:
squared_numbers.append(num ** 2)
print(squared_numbers)
输出结果 >>> [1, 4, 9, 16, 25]
但是列表解析提供了一种更简洁和简单的语法来完成这个任务。通过将一个表达式应用到可迭代对象的每个项来创建新的列表。
下面是使用列表解析表达式的简洁替代方案:
numbers = [1, 2, 3, 4, 5]
squared_numbers = [num ** 2 for num in numbers]
print(squared_numbers)
输出结果 >>> [1, 4, 9, 16, 25]
在这里,列表解析创建一个包含 numbers
列表中每个数字的平方的新列表。
带有条件过滤的列表解析
你还可以在列表解析表达式中添加过滤条件。看看这个例子:
numbers = [1, 2, 3, 4, 5]
odd_numbers = [num for num in numbers if num % 2 != 0]
print(odd_numbers)
输出结果 >>> [1, 3, 5]
在这个例子中,列表解析创建一个只包含 numbers
列表中奇数的新列表。
Python 中的字典解析
和列表解析类似,字典解析允许你从现有的可迭代对象中创建字典。
假设你有一个 fruits
列表。你想创建一个 key-value 对为 fruit:len(fruit)
的字典。
这是如何用循环完成这个任务的:
fruits = ["apple", "banana", "cherry", "date"]
fruit_lengths = {}
for fruit in fruits:
fruit_lengths[fruit] = len(fruit)
print(fruit_lengths)
输出 >>> {'apple': 5, 'banana': 6, 'cherry': 6, 'date': 4}
现在让我们写出等效的字典推导式:
fruits = ["apple", "banana", "cherry", "date"]fruit_lengths = {fruit: len(fruit) for fruit in fruits}print(fruit_lengths)
输出 >>> {'apple': 5, 'banana': 6, 'cherry': 6, 'date': 4}
这个字典推导式创建了一个字典,其中键是水果,值是水果名称的长度。
带有条件过滤的字典推导式
让我们修改我们的字典推导式来包含一个条件:
fruits = ["apple", "banana", "cherry", "date"]long_fruit_names = {fruit: len(fruit) for fruit in fruits if len(fruit) > 5}print(long_fruit_names)
输出 >>> {'banana': 6, 'cherry': 6}
在这里,字典推导式创建了一个字典,其中水果名称作为键,它们的长度作为值,但只限于名称超过5个字符的水果。
3. 使用上下文管理器有效处理资源
Python中的上下文管理器可以帮助您高效地管理资源。通过使用上下文管理器,您可以轻松设置和清理(清除)资源。上下文管理器的最简单和最常见的示例是文件处理。
看一下下面的代码片段:
filename = 'somefile.txt'file = open(filename,'w')file.write('Something')
它没有关闭文件描述符,导致资源泄漏。
print(file.closed)输出 >>> False
您可能会做出以下修改:
filename = 'somefile.txt'file = open(filename,'w')file.write('Something')file.close()
虽然这尝试关闭描述符,但它没有考虑在写操作过程中可能出现的错误。
好吧,现在您可以实施异常处理,尝试打开一个文件并在没有任何错误的情况下写入一些内容:
filename = 'somefile.txt'file = open(filename,'w')try: file.write('Something')finally: file.close()
但这很冗长。现在看看下面使用with
语句的版本,它支持上下文管理器的open()
函数:
filename = 'somefile.txt'with open(filename, 'w') as file: file.write('Something')print(file.closed)
输出 >>> True
我们使用with
语句创建一个上下文,在该上下文中打开文件。这确保了在执行退出with
块时正确关闭文件,即使在操作过程中引发异常也是如此。
4. 使用生成器进行内存高效处理
生成器提供了一种优雅的处理大型数据集或无限序列的方式,提高代码效率并减少内存消耗。
什么是生成器?
生成器是使用yield
关键字一次返回一个值的函数,它在调用之间保持其内部状态。与一次计算所有值并返回一个完整列表的常规函数不同,生成器在需要时计算和生成值,使其适用于处理大型序列。
发电机是如何工作的?
让我们了解一下发电机的工作原理:
- 发生器函数的定义方式与常规函数相同,但是您会使用
yield
关键字而不是return
来生成一个值。 - 当您调用发电机函数时,它会返回一个发电机对象。您可以通过循环遍历或使用
next()
调用来迭代它。 - 当遇到
yield
语句时,函数的状态被保存,并且生成的值被返回给调用者。函数的执行暂停,但其本地变量和状态被保留。 - 当再次调用发电机的
next()
方法时,执行从暂停的位置恢复,函数继续执行直到下一个yield
语句。 - 当函数退出或引发
StopIteration
异常时,发电机被认为已耗尽,进一步调用next()
将引发StopIteration
异常。
创建发电机
您可以使用发电机函数或发电机表达式来创建发电机。
这是一个发电机函数的示例:
def countdown(n): while n > 0: yield n n -= 1# 使用发电机函数for num in countdown(5): print(num)
输出 >>> 5 4 3 2 1
发电机表达式类似于列表推导,但它们创建的是发电机而不是列表。
# 使用发电机表达式创建一个平方序列squares = (x ** 2 for x in range(1, 6))# 使用发电机表达式for square in squares: print(square)
输出 >>> 1 4 9 16 25
5. 利用集合类
我们将通过学习两个有用的集合类来结束本教程:
- NamedTuple
- Counter
使用命名元组使元组更易读
在Python中,命名元组是内置元组类的子类,在collections模块中。但它提供了命名字段。这使得它比常规元组更易读和更易于自我文档化。
这是一个创建一个简单的三维空间点元组并访问各个元素的示例:
# 3D点元组coordinate = (1, 2, 3)# 使用元组解包访问数据x, y, z = coordinateprint(f"X坐标:{x},Y坐标:{y},Z坐标:{z}")
输出 >>> X坐标:1,Y坐标:2,Z坐标:3
这是命名元组版本:
from collections import namedtuple# 定义一个Coordinate3D命名元组Coordinate3D = namedtuple("Coordinate3D", ["x", "y", "z"])# 创建一个Coordinate3D对象coordinate = Coordinate3D(1, 2, 3)print(coordinate)# 使用命名字段访问数据print(f"X坐标:{coordinate.x},Y坐标:{coordinate.y},Z坐标:{coordinate.z}")
输出 >>>Coordinate3D(x=1, y=2, z=3)X坐标:1,Y坐标:2,Z坐标:3
因此,通过使用NamedTuples,您可以比使用普通元组编写更清晰和更易于维护的代码。
使用Counter简化计数
Counter是collections模块中的一个类,用于计算可迭代对象(如列表或字符串)中元素的频率。它返回一个带有{element:count}
键值对的Counter对象。
让我们以计算长字符串中字符频率的示例为例。
以下是使用循环计算字符频率的传统方法:
word = "难以理解性"# 初始化一个空字典来计数字符char_counts = {}# 计算字符频率for char in word: if char in char_counts: char_counts[char] += 1 else: char_counts[char] = 1# 打印出char_counts字典print(char_counts)# 找到最常见的字符most_common = max(char_counts, key=char_counts.get)print(f"最常见的字符: '{most_common}' (出现 {char_counts[most_common]} 次)")
我们手动遍历字符串,更新字典以计算字符频率,并找到最常见的字符。
输出 >>> {'难': 5, '以': 2, '理': 1, '解': 1, '性': 1}最常见的字符: '难' (出现 5 次)
现在,让我们使用Counter类以Counter(iterable)
的语法执行相同的任务:
from collections import Counterword = "难以理解性"# 使用Counter计算字符频率char_counts = Counter(word)print(char_counts)# 找到最常见的字符most_common = char_counts.most_common(1)print(f"最常见的字符: '{most_common[0][0]}' (出现 {most_common[0][1]} 次)")
输出 >>> Counter({'难': 5, '性': 1, '以': 1, '理': 1, '解': 1})最常见的字符: '难' (出现 5 次)
因此,Counter
提供了一种更简单的方式来计算字符频率,而无需手动迭代和管理字典。
总结
我希望您能找到一些有用的技巧,以补充您的Python工具箱。如果您想学习Python或准备进行编码面试,以下是一些资源可以帮助您的学习之旅:
愉快的学习吧!
[Bala Priya C](https://twitter.com/balawc27)是来自印度的开发人员和技术作家。她喜欢在数学、编程、数据科学和内容创作的交叉点上工作。她的兴趣和专长领域包括DevOps、数据科学和自然语言处理。她喜欢阅读、写作、编码和咖啡!目前,她正在通过撰写教程、指南、观点文章等向开发者社区学习和分享她的知识。