PEP 8 – Python 代码风格指南中文版(八)

  • 编程建议(3)

  • 在return语句中保持一致性。

函数中的所有return语句要么都返回一个表达式,要么都不返回。如果任何return语句返回了一个表达式,那么任何没有返回值的return语句应该明确地声明为return None,并且在函数的末尾(如果可达)应该有一个明确的return语句:

# 正确的:
def foo(x):
    if x >= 0:
        return math.sqrt(x)
    else:
        return None

def bar(x):
    if x < 0:
        return None
    return math.sqrt(x)


# 错误的:
def foo(x):
    if x >= 0:
        return math.sqrt(x)

def bar(x):
    if x < 0:
        return
    return math.sqrt(x)

解释:

这意味着,对于函数的返回行为,你应该有一个清晰的策略。要么每个返回点都返回一个具体的值,要么在某些情况下(如提前退出函数)返回None来明确表明没有返回值,并且在函数逻辑正常结束时,无论是否达到这个点,都应该有一个显式的return语句(如果函数逻辑允许它被执行到这一点)。这样做可以提高代码的可读性和可维护性。

  • 使用 startswith() 和 endswith() 方法代替字符串切片来检查前缀或后缀。

startswith() 和 endswith() 方法更简洁且更不容易出错:

# 正确的:
if foo.startswith('bar'):

# 错误的:
if foo[:3] == 'bar':

解释

在Python中,当你需要检查一个字符串是否以某个特定的前缀或后缀开始时,你有几种方法可以实现这一点。但是,PEP-8建议优先使用str.startswith()str.endswith()这两个内置方法,而不是通过字符串切片(string slicing)的方式来进行检查。

使用这种方法的好处有:

  1. 可读性startswith()endswith()这两个方法的名称直接说明了它们的功能,即检查字符串是否以某个特定的前缀或后缀开始。这使得代码更加易于阅读和理解。

  2. 安全性:使用字符串切片来检查前缀或后缀时,你需要精确地计算切片的起始和结束索引。如果索引计算错误,可能会导致意外的结果或错误。而startswith()endswith()方法则不需要你担心这些问题,它们会自动处理。

  3. 灵活性startswith()endswith()方法还允许你指定检查的起始位置(通过start参数)和结束位置(通过end参数),这提供了额外的灵活性。此外,它们还可以接受一个元组作为参数,以检查字符串是否以元组中的任何一个前缀或后缀开始。

  4. 效率:虽然在实际应用中,这两种方法的性能差异可能微乎其微,但使用startswith()endswith()方法通常被认为是更加“Pythonic”的方式,即更符合Python的编程风格和最佳实践。

  • 对象类型比较应该始终使用isinstance()而不是直接比较类型:

# 正确的:
if isinstance(obj, list):

# 错误的:
if type(obj) is type(1):

解释

在Python中,当你需要检查一个对象是否属于某个类型时,有两种基本的方式可以做到这一点:使用isinstance()函数,或者直接使用==操作符与type()函数结合来比较类型。然而,PEP-8建议我们应该优先使用isinstance()函数来进行类型检查。

为什么推荐使用isinstance()

  1. 多态性支持isinstance()不仅可以检查对象是否属于指定的类型,还可以检查对象是否属于该类型的任何子类。这种能力对于支持多态性的Python代码来说是非常有用的。相比之下,直接比较类型(如type(obj) == SomeClass)则不会考虑继承关系。

  2. 灵活性isinstance()允许你一次性检查多个类型,通过传递一个类型元组作为第二个参数。这样,你就不必为每个可能的类型编写单独的比较语句。

  3. 可读性和可维护性:使用isinstance()可以使代码更加清晰和易于理解,因为它直接表达了“这个对象是否是这个类型或这个类型的子类的实例”的意图。此外,当类型结构发生变化时(比如添加了新的子类),使用isinstance()的代码更有可能保持有效,而直接比较类型的代码则可能需要更新。

  4. 遵循Python的哲学:Python的设计哲学之一是“有一种且只有一种显而易见的方式来做一件事”(There should be one-- and preferably only one --obvious way to do it)。在这个问题上,isinstance()就是Python社区推荐的、显而易见的方式来进行类型检查。

  • 对于序列(字符串、列表、元组),利用空序列为假的特性:

# 正确的:
if not seq:
if seq:

# 错误的:
if len(seq):
if not len(seq):

解释:在Python中,当你需要对字符串、列表、元组等序列类型进行条件判断时,可以直接利用这些序列为空(即不包含任何元素)时其布尔值为False的特性。这意味着你不需要显式地检查序列的长度是否为0,只需要在if语句等条件表达式中直接使用序列作为条件即可。

例如,检查一个列表是否为空,可以这样写:

if my_list:
    # 列表不为空,执行某些操作
else:
    # 列表为空,执行其他操作

而不需要写成:

if len(my_list) > 0:
    # 列表不为空,执行某些操作
else:
    # 列表为空,执行其他操作

虽然第二种写法在逻辑上是等价的,但第一种写法更加简洁,且直接利用了Python中空序列为假的特性。同样的逻辑也适用于字符串和元组等其他序列类型。

  • 不要编写依赖于重要尾随空格的字符串字面量。

这种尾随空格在视觉上无法区分,并且一些编辑器(或最近的reindent.py)会修剪它们。

解释

在Python中,字符串字面量通常用于表示文本数据。然而,有时候在字符串的末尾可能会包含一些看似不重要但实际上对字符串内容有影响的空格字符。这些尾随空格(trailing whitespace)在大多数情况下可能只是由于编码习惯或复制粘贴时的不小心而引入的,但在某些特定情况下,它们可能具有实际意义,比如用于格式化输出或作为字符串的一部分参与比较。

然而,PEP-8建议我们避免编写依赖于这些重要尾随空格的字符串字面量。原因主要有两个:

  1. 视觉上难以区分:尾随空格在文本编辑器中通常很难被注意到,尤其是当它们位于字符串的末尾时。这可能导致其他开发者在阅读或修改代码时忽略这些空格,从而引入潜在的错误。

  2. 自动工具会修剪它们:一些文本编辑器或代码格式化工具(如reindent.py,虽然它主要用于重新缩进代码,但也可能对字符串中的空格进行处理)会自动修剪字符串末尾的空格。如果代码依赖于这些空格来正确工作,那么使用这些工具后可能会导致代码行为异常。

因此,为了编写更加健壮和可维护的代码,我们应该尽量避免在字符串字面量中包含重要的尾随空格。如果确实需要这些空格,可以考虑使用其他方式来表示它们,比如使用转义字符(虽然对于空格来说通常不推荐这样做,因为它会使字符串看起来更加复杂)或将其存储在单独的变量中。然而,在大多数情况下,最好的做法是简单地避免在字符串末尾添加不必要的空格。

  • 不要使用“==”来将布尔值与True或False进行比较。

# 正确的:
if greeting:

# 错误的:
if greeting == True:

# 更糟糕的:
if greeting is True:

解释:

在Python中,直接对布尔值进行“== True”或“== False”的比较是多余的,因为布尔值本身就是True或False,直接用作条件表达式即可。例如,if x == True: 可以简写为 if x:,而 if x == False: 可以改写为 if not x:。这样的写法更加简洁,也符合Python的惯用风格。

  • 在try...finally语句的finally子句中使用流程控制语句return、break或continue,当这些流程控制语句会跳出finally子句时,这种做法是不被推荐的。

这是因为这样的语句会隐式地取消任何正在通过finally子句传播的活跃异常。

# 错误的:
def foo():
    try:
        1 / 0
    finally:
        return 42

解释:

在Python中,try...finally语句用于执行一段代码,无论是否发生异常,finally子句中的代码都会被执行。如果在finally子句中使用了return、break或continue语句,并且这些语句会导致控制流跳出finally子句(例如,return会使函数返回,break会跳出最近的循环,continue会跳过当前循环的剩余部分并继续下一次迭代),那么任何在try块中抛出但尚未被捕获的异常,或者在try块和finally子句之间抛出的异常,都会被隐式地取消(即不会被传播到调用者)。这可能会导致程序的行为变得难以预测和调试。

因此,PEP 8(Python的官方编码风格指南)建议避免在finally子句中使用这些可能导致控制流跳出的语句。如果确实需要在finally子句中执行某些清理操作,并且这些操作可能会抛出异常,那么应该确保这些异常被适当地捕获和处理,以避免干扰到原始异常的传播。如果需要在finally子句之后立即返回或退出循环,考虑将相关的逻辑重构到try块或finally块之外的适当位置。

     相关文章:

PEP 8 – Python 代码风格指南中文版(一)

PEP 8 – Python 代码风格指南中文版(二)

PEP 8 – Python 代码风格指南中文版(三)

PEP 8 – Python 代码风格指南中文版(四)

PEP 8 – Python 代码风格指南中文版(五)

PEP 8 – Python 代码风格指南中文版(六)

PEP 8 – Python 代码风格指南中文版(七)

PEP 8 – Python 代码风格指南中文版(八)

PEP 8 – Python 代码风格指南中文版(九) 

  • 17
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值