Python程序员常犯的错误以及如何解决这些问题

136 阅读7分钟

Python是世界上最流行的编程语言之一。它是一种面向对象的高级编程语言。Python以其代码的可读性、极简主义和效率而闻名。

开发人员在编写Python代码时有很大的灵活性,因为它是一种解释型语言。但巨大的自由带来了巨大的责任,甚至更大的错误空间。在这篇文章中,我们将回顾Python程序员常犯的10个错误以及如何解决这些错误。

不正确的缩进

在Python中,缩进表示某一行代码是否属于一个代码块中的前一个语句。Python 的官方风格指南 (PEP 8) 推荐缩进四个空格。然而,你可以灵活地选择任何数量的空格,也可以使用Tab键。无论你喜欢哪种缩进方式,Python都要求一件事:一致性。

要修复一个缩进错误,请尝试一下:

  • 致力于使用空格或Tab键,但不要把它们结合起来。你要格外注意,因为如果产生的缩进看起来是一样的,你可能不会意识到你已经结合了制表符和空格。你可以尝试使用一个提供搜索/替换工具的Python集成开发环境或代码编辑器,用空格替换制表符,或者反过来。
  • 如果使用空格,请与你使用的空格数量保持一致。你不必使用 PEP 8 推荐的 4 个空格,但无论你选择哪个数字,都要坚持下去!

由相同的模块名称引起的导入错误

你可能正在导入一个你确信在 Python 标准库中的内置模块,但令你吃惊的是,解释器返回 "ImportError"。这个问题通常出现在开发者将一个与标准库的一个内置模块有相同名称的文件导入他们的库中。在这种情况下,Python 会优先考虑你已经安装的相同名字的模块,而不是标准库的内置模块。解决办法是什么?简单地将你库中的文件重命名为一个不与标准库模块共享的独特名字。

使用易变的默认参数

另一个常见问题出现在为默认参数指定可变数据类型时。Python 只在创建函数时对可变数据类型的默认值进行一次评估。它不会为任何后续的函数执行初始化默认值。如果你在代码中只进行一次函数调用,你可能不会注意到任何异常,但是如果你第二次调用它,Python 将使用在第一次函数调用时评估的缺省。

比方说,你正在使用一个可变的数据类型,如列表。解释器将使用最初定义函数时创建的同一个 list。这段代码揭示了当你追加该列表时可能发生的令人费解的行为:

def some_func(default_arg=[]):
    default_arg.append("some_string")
    return default_arg
 
print(some_func())
print(some_func())
print(some_func([]))
print(some_func())

解决这个编程错误的一个方法是**将 "无 "作为默认值。**你以后可以检查传递给函数的任何值是否与该参数相对应:

def some_func(default_arg=None):
    if default_arg is None:
        default_arg = []
    default_arg.append("some_string")
    return default_arg
 
print(some_func())
print(some_func())
print(some_func([]))
print(some_func())

在结构性句子的结尾处忘记冒号

如果你收到语法错误,你可能在句子的末尾忘记了冒号。在Python代码中,每个结构句以冒号结束。这也适用于函数标题,冒号触发了函数中后续行的缩进。对于初学Python的开发者来说,这是一个常见的编程错误。要解决这个问题,只需演练这个规则,直到它成为第二天性:每个结构句以冒号结尾!

与小括号或大括号不一致

这对Python初学者来说是一个令人惊讶的常见错误。就像数学一样,开放和封闭的小括号和大括号的数量必须匹配,才能使语句可读。确保审查你的代码,并确保每个开放的小括号或大括号都有一个相应的封闭的小括号来完成其思想。

init函数的应用不正确

作为构造函数使用,init函数创建一个对象或为一个新的类对象分配内存。当从一个类中创建一个对象时,init函数被用作构造函数,并允许该类初始化该类的属性。换句话说,它是专门用来设置数值的。然而,Python 开发者常犯的一个错误是试图用这个方法来返回值。要解决这个问题,只需了解init方法在Python中的功能是专门用来作为构造函数的。

在不使用类名的情况下修改类的变量值

作为一种面向对象的语言,类变量和实例变量在 Python 中的操作是不同的。与实例变量不同,类变量是由整个类中的实例共享的。如果你在不使用类名的情况下修改一个类变量,就会创建一个与类变量同名的实例变量。与类变量同名的新实例变量实际上是类变量的影子,所以如果你试图第二次修改一个类变量,代码中的对象将引用实例变量。为了解决这个错误,在修改类变量时一定要使用类的名字,这样所有的对象也会收到更新的值。

对 Python 范围规则的误解

如果你的代码返回 "UnboundLocalError",你可能误解了 Python 的范围规则。这是 Python 开发者在使用列表时遇到的一个常见错误。

Python 独特的作用域分析是基于 LEGB 规则,即局部、封闭、全局、内置规则。按照 LEGB 规则的顺序,Python 将首先假定在一个范围内分配的任何变量都是该范围本地变量,并将覆盖外部范围内的任何同名变量。这意味着当你分配变量时按预期运行的代码,后来当你再次调用该函数时可能会返回 "UnboundLocalError"。

在这个例子中,我们以运行如预期的代码开始:

x = 10
def bar():
    print(x)
bar()

当我们赋值一个变量时,这段代码返回 "UnboundLocalError"。根据 LEGB 规则的顺序,Python 将 "x" 的这个新赋值识别为局部变量,而不是外部范围变量:

x = 10
def foo():
    print(x)
    x += 1
foo()

要解决 "UnboundLocalError",你只需要添加一个赋值语句,明确声明这个变量是全局的:

x = 10
def foobar():
    global x
    print(x)
    x += 1
foobar()

误解了 Python 在闭包中绑定变量的方式

Python 很晚才把它的变量绑定在闭包中。这意味着它调用的是第一次调用受影响的函数时返回的变量值。对于你的代码来说,这可能并不总是有问题的,但如果是这样,你可以通过创建一个闭包来解决这个问题,该闭包将立即与它的参数绑定,例如一个默认参数。

关于闭包和变量的更多信息,请查看这个关于Python 闭包和变量的快速概述。

穷举迭代器

对于早期的 Python 开发者来说,理解迭代器和生成器都可以被耗尽是很重要的。从 Python2 过渡到 Python3 的开发者可能特别会遇到这个问题。Python3 有更多的生成器,这有助于使它更有效率。然而,对于那些面临着在Python2中没有的新挫折的人来说,这可能很困难。

这种类型的错误可能是这样的:你可能在Python2中调用一个迭代器函数,比如zip,来组合两个列表,并试图在以后打印出这个列表。现在,如果你在 Python3 中使用同样的代码,它将不会一次返回所有的值给你。这是因为你已经用尽了迭代器,它没有剩余的值可以返回。

你可以通过简单地从一开始就把一个函数转换为一个列表来解决这个问题。虽然你可以用尽一个迭代器,但你不能用尽一个列表。 查看这个资源以了解更多关于Python 中迭代器的细节。

总结和下一步

我们赞扬你为成为一个全面的 Python 开发者而付出的时间和勇气随着从机器学习到数据科学的应用,Python不会很快消失。