这篇文章整理了50个简洁的提示,可以提高您的代码可读性和效率。这些提示来自个人项目、彻底的代码审查和与资深开发人员的启发性讨论。
无论您是新手还是经验丰富的开发人员,这篇文章都应该能够帮助您学到一些东西。
这个列表包括常见的Python模式、核心概念和最佳实践。
由于没有特定的顺序,请随时直接跳转到您感兴趣的部分。
不再废话,让我们来看看吧
1 — 三元操作符
Python中的三元操作符提供了一种内联方式来编写条件表达式。当您需要根据条件为变量分配一个值时,它们特别有用。
age = 25
status = "成年人" if age >= 18 else "未成年人"
print(status)
# 成年人
在这个示例中,如果年龄大于或等于18,status变量的值将是"成年人",否则将是"未成年人"。
当它们用于列表推导式时,三元操作符非常有用
scores = [100, 46, 54, 23, 20, 99]
threshold = 50
results = ["通过" if score > threshold else "未通过" for score in scores]
print(results)
# ['通过', '未通过', '通过', '未通过', '未通过', '通过']
或者用于lambda函数:
scores = [100, 46, 54, 23, 20, 99]
threshold = 50
results = map(lambda score: "通过" if score > threshold else "未通过", scores)
print(results)
# ['通过', '未通过', '通过', '未通过', '未通过', '通过']
2 — 上下文管理器
想象一下,您用Python打开一个文件,在文件中写入了一些行,然后在您甚至无法关闭它之前发生了异常。
虽然这对于初学者开发人员来说似乎不是什么问题,但它会占用一个永远不会被清除的内存资源(文件描述符),并且可能会阻止部分数据被写入。
上下文管理器可以帮助您避免这种情况。它们用于管理资源,并确保这些资源被正确初始化和清理。
它们通过封装资源管理的逻辑在上下文管理器对象内,有助于编写更可读和可维护的代码。
→ 最常见的上下文管理器是使用open创建的
with open('file.txt', 'r') as file:
# 如果在这里发生了任何错误
data = file.read()
open()函数返回一个文件对象,它充当上下文管理器。当with语句内部的块退出时,它会自动关闭文件,确保正确的清理。
您还可以在其他情况下使用上下文管理器来处理:
数据库连接:
import psycopg2
with psycopg2.connect(database='mydb') as conn:
cursor = conn.cursor()
cursor.execute('SELECT * FROM table')
results = cursor.fetchall()
在这个示例中,psycopg2库的connect()方法返回一个连接对象,它充当上下文管理器,当块退出时会自动关闭连接。
锁定资源:
import threading
lock = threading.Lock()
def some_function():
with lock:
# 临界代码段
在这里,threading模块的Lock()对象被用作上下文管理器,以确保一次只有一个线程可以访问关键代码段。
3 — 创建自己的上下文管理器!
有时您可能需要定义自己的上下文管理器。
为此,您需要定义一个实现__enter__()和__exit__()方法的类:
以下是一个测量代码块执行时间的自定义上下文管理器示例:
示例1:计时器
import time
class Timer:
def __enter__(self):
self.start_time = time.time()
def __exit__(self, exc_type, exc_val, exc_tb):
elapsed_time = time.time() - self.start_time
print(f"执行时间:0.0556秒")
这个示例非常简单。让我们看看另一个模仿open行为的示例。
示例2:自定义文件打开器
class WritableFile:
def __init__(self, file_path):
self.file_path = file_path
def __enter__(self):
print("打开文件")
self.file_obj = open(self.file_path, mode="w")
return self.file_obj
def __exit__(self, exc_type, exc_val, exc_tb):
if self.file_obj:
self.file_obj.close()
print("文件成功关闭")
虽然这些示例相当简单,但它们应该为您提供一个构建更高级上下文管理器的起点代码段,其中执行适当的资源清理。
4 — 枚举
如果您想要迭代一个序列并同时跟踪每个项目的索引,那么应该使用enumerate函数。
它通过消除手动管理单独的索引变量,使代码更加简洁。
fruits = ['苹果', '香蕉', '橙子']
for index, fruit in enumerate(fruits):
print(f"索引:{index},水果:{fruit}")
# 索引:0,水果:苹果
# 索引:1,水果:香蕉
# 索引:2,水果
:橙子
5 — Zip
zip函数允许同时迭代多个序列:
names = ['Alice', 'Bob', 'Charlie']
ages = [25, 30, 35]
for name, age in zip(names, ages):
print(f"姓名:{name},年龄:{age}")
# 姓名:Alice,年龄:25
# 姓名:Bob,年龄:30
# 姓名:Charlie,年龄:35
作为有趣的用例,zip还可以从两个列表创建一个字典,其中键来自第一个列表,值来自第二个列表。
keys = ['a', 'b', 'c']
values = [1, 2, 3]
my_dict = dict(zip(keys, values))
print(my_dict)
# {'a': 1, 'b': 2, 'c': 3}
6 — 使用sorted对复杂对象进行排序
sorted函数允许您根据某些属性对复杂对象进行排序。
要访问要排序的属性值,您必须使用自定义的key函数。
假设您要根据"age"键对这些人进行排序。
people = [
{'name': 'Alice', 'age': 25},
{'name': 'Bob', 'age': 30},
{'name': 'Charlie', 'age': 20}
]
只需将key参数设置为指向age值。
sorted_people = sorted(people, key=lambda x: x['age'])
print(sorted_people)
# [{'name': 'Charlie', 'age': 20}, {'name': 'Alice', 'age': 25}, {'name': 'Bob', 'age': 30}]
如果将字典替换为对象,它的工作方式也是一样的:
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
people = [
Person('Alice', 25),
Person('Bob', 30),
Person('Charlie', 20)
]
sorted_people = sorted(people, key=lambda x: x.age)
print([person.name for person in sorted_people])
print(sorted_people)
# ['Charlie', 'Alice', 'Bob']
7 — 使用生成器节省内存
Python生成器是一种可迭代类型,可用于即时生成一系列值,而不必将它们全部存储在内存中。它们使用yield关键字定义,而不是return。
这是一个计算斐波那契数的简单生成器。
def fibonacci_generator():
a, b = 0, 1
while True:
yield a
a, b = b, a + b
调用这个函数实际上不会运行它。它创建并返回一个生成器对象。
fib = fibonacci_generator()
fib
#
这个生成器对象仅在传递给next函数时生成斐波那契值。
next(fb)
# 0
next(fb)
# 1
next(fb)
# 1
next(fb)
# 2
或者使用for循环迭代(在底层基本上调用了next函数)。
这是内存高效的,因为它避免了预先生成整个(无限)序列。
生成器的一个自然用例是逐行(或分块)读取大型数据集
def read_large_file(filename):
with open(filename, 'r') as file:
for line in file:
yield line
#逐行处理而不是加载整个文件
file_generator = read_large_file('large_file.txt')
for line in file_generator:
process_line(line) #处理
8 — 使用f-strings改进字符串格式化!
f-strings改进了字符串格式化语法:它们是字符串文字,以f开头,包含用于替换为其值的表达式的花括号。
语法非常简单。
name = "Alice"
age = 25
print(f"你好{name},你今年{age}岁!")
# 你好Alice,你今年25岁!
甚至可以用它来计算任意表达式,比如函数调用:
def add_numbers(a, b):
return a + b
x = 5
y = 3
print(f"{x}和{y}的和是{add_numbers(x, y)}。") # 输出:5和3的和是8。
带有特定精度的浮点数:
pi = 3.14159265359
print(f"π的值约为{pi:.2f}。")
# 输出:π的值约为3.14。
对象。
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
person = Person("Bob", 25)
print(f"姓名:{person.name},年龄:{person.age}")
# 输出:姓名:Bob,年龄:25
字典(在字典键周围使用简单的引号)
data_scientist = {'name': 'Ahmed BESBES', 'age': 32}
f"This data scientist is {data_scientist['name']}, aged {data_scientist['age']}."
这个数据科学家是Ahmed BESBES,年龄是32岁。
9 — 使用迭代器协议构建可迭代对象
您是否曾经想知道简单的for循环在幕后是如何工作的?
答案不在for循环本身,而是在被迭代的对象中(也称为可迭代对象)。这些可以是列表、字典或集合。
事实上,可迭代对象支持迭代器协议并实现__iter__()
和__next__
()双下划线方法。
这些双下划线方法是使得可以迭代一组元素或执行自定义迭代的核心方法。
下面是一个自定义迭代器的示例,它接受一个数字列表并在运行时生成它们的平方:
class SquareIterator:
def
__init__(self, numbers):
self.numbers = numbers
self.index = 0
def __iter__(self):
return self
def __next__(self):
if self.index >= len(self.numbers):
raise StopIteration
square = self.numbers[self.index] ** 2
self.index += 1
return square
在__iter__()
方法中,返回迭代器对象本身。当初始化迭代器时调用此方法。
在__next__()
方法中,定义检索迭代中下一个元素的逻辑。
当没有更多元素可以迭代时,此方法应引发StopIteration异常。(请注意,索引在这里递增以跟踪其位置)
我们可以像这样使用这个自定义迭代器:
numbers = [1, 2, 3, 4, 5]
iterator = SquareIterator(numbers)
for square in iterator:
print(square)
# 1
# 4
# 9
# 16
# 25
10 — 创建自定义异常类以记录您的代码
我从未考虑过创建自定义异常类。我只依赖于内置的异常。
事实是,在大型代码库中使用它们会带来多重好处。
它们允许您创建更具体和有意义的异常,准确表示代码中发生的错误或异常情况。这有助于调试提高了协作:
如果您的同事开始向同一存储库推送代码,他们更容易通过具有明确消息而不是通用的ValueError异常来调试错误
这是一个自定义异常类的示例,当输入字符串长度超过阈值时引发异常。
class NameTooLongError(Exception):
"""用于过长名称的自定义异常。"""
def __init__(self, name, max_length):
self.name = name
self.max_length = max_length
super().__init__(f"名称'{name}'太长,允许的最大长度为{max_length}个字符。")
def process_name(name):
max_length = 10 # 允许的最大名称长度
if len(name) > max_length:
raise NameTooLongError(name, max_length)
else:
print("名称处理成功:", name)
# 示例用法
try:
input_name = "AVeryLongName"
process_name(input_name)
except NameTooLongError as e:
print("错误:", e)
本文由mdnice多平台发布