写点什么

Python 开发人员常犯的这 7 个错误,可能是“致命”的

  • 2020-10-28
  • 本文字数:2402 字

    阅读完需:约 8 分钟

Python 开发人员常犯的这7个错误,可能是“致命”的

本文最初发表于 Towards Data Science 博客,经原作者 Anupam Chugh 授权,InfoQ 中文站翻译并分享。


Python 无疑是当今使用最广泛的编程语言。它之所以如此流行,很大程度上是由于简单的语法和可读性,这使得它非常容易使用。初学者之所以喜欢 Python,是因为它给人一种感觉就像是用英语写一段伪代码一样。


但是,无论你有多么丰富的经验,也无论你已经研究过多少种语言,切换到 Python 并不能保证你能做到平稳过渡。具有面向对象编程背景的开发人员很容易忽略 Python 的惯用特性。这样一来,他们很可能会误用编程结构,从而可能出现难以发现的、不可预见的错误。更糟糕的是,这些错误大多很难发现,并且可能会给生产带来麻烦。


在本文中,我将列出程序员(通常是菜鸟)可能会犯的常见错误。此外,我还将介绍如何避免这些错误,以便编写出更好的、无错误的 Python 代码。闲话少叙,言归正题。

错误一:编写过于风格化的代码

这是 Python 初学者的一个典型特征。为了编写类似伪英语的高级代码,他们的代码库中会出现以下类型的代码片段:


if x == 1 or 2
复制代码


奇怪的是,这可能看起来并不那么糟糕。基本上,这段代码的意思是变量 x 需要为 1 或 2 才能满足条件。但是,这样的代码片段会过于风格化,并会带来可读性问题。


下面这段替代代码,检查列表中的值,更容易让人理解。


if x in [1,2]
复制代码

错误二:无必要的比较运算符:None 和 Zero

具有 Java 背景的程序员都知道需要多少 null 检查(特别是在 Java 8 之前的版本中)。所以,在 Python 中,使用像下面这样的比较运算符也就不足为奇了:


a == Noneb != None
复制代码


但在上面的例子中,实际上,我们可以利用 Python 编写代码的方式来增强可读性:


a is Noneb is not None
复制代码


同样,对于 0,值得注意的是,在条件逻辑中实际上并不需要使用比较运算符。0 被解释为 false,而非零数字被视为 true。

错误三:使用长长的条件按位逻辑链

在大多数语言(包括 Swift、Java、Kotlin)中,我们都知道要用以下方式编写某些比较逻辑:


if a < b and b < c
复制代码


与不能在非关联优先级中使用相邻运算符的大多数语言不同,Python 提供了编写链式赋值的能力,如下段代码所示:


if a < b < c
复制代码


这样写,就可以避免按位运算符。

错误四:使用 type() 代替 isinstance(),反之亦然

typeisinstance()是 Python 中用于类型检查的两个广泛使用的内置函数。


通常,开发人员刚入门 Python 时,会将这两个函数视为相似的函数,并将它们互换着使用。现在,由于type()isinstance()有一些细微的区别,这可能会埋下无法预料的错误。


isinstance()函数用于检查对象是否为指定类的实例,同时还要负责继承。另一方面,type()只检查引用类型是否相同并丢弃子类型。


因此,下面的代码使用type()isinstance()分别得到了不同的结果:


class Vehicle:passclass Car(Vehicle):passisinstance(Car(), Vehicle) # returns Truetype(Car()) == Vehicle # returns False
复制代码


类似地,下面的代码将布尔值视为 int 的实例(因为 true 和 false 基本上被视为 1 和 0),但是使用不同的类型函数就给出了不同的结果。


type(True) == int # falseisinstance(True, int) # trueisinstance(False, int) # true
复制代码


因此,理解 Python 的这两种类型检查器函数之间的区别是很重要的,不要将它们相互混淆。

错误五:混淆作用域中的局部变量和全局变量

Python 中的作用域规则看起来非常简单,但很容易被误解。例如,以下代码在函数中使用了全局变量:


a = 10def printMe():print(a)printMe() # prints 10
复制代码


现在,如果我们只是通过修改函数中的变量来稍微调整上面的代码,就会得到一个错误的结果:


a = 20def printA():print(a)a = 10print(a) # gives 20printA() # gives error as a is referenced before assigned
复制代码


一旦我们修改了函数中的全局变量,Python 就会将其视为局部变量,从而遮蔽了全局变量。甚至在复制之前的 print 语句也没有执行。


为确保这种名称冲突不会导致错误,我们可以在局部函数中的全局变量后面附加一个global关键字。更好的做法是将全局变量(如果你实际需要使用的话)放在一个单独的类中,这样,你就可以始终使用带有类名的全局变量了。

错误六:可变的默认参数

使用默认参数,是 Python 中的一种常见习惯。它有助于防止在调用时函数中出现一长串参数。


现在,在 Python 中,列表、字典和集合都是可变类型。因此,设置默认值可能会导致意外的结果,如下所示:


def addToList(x, a=[]):a.append(x)return alistOne = addToList(5)#prints [5]anotherList = addToList(10)# [5, 10]
复制代码


如你所见,第二个列表包含之前添加的元素,因为函数中的可变默认参数跨状态存储这些元素。


Python 中可变默认对象的问题在于,它是在定义函数时计算的。这会导致变异值也保留之前的内容。


为避免此类严重错误,请将None设置为默认值,并在函数中分配可变变量,如下所示:


def addElement(x, a=None):if not a:a = []a.append(x)return a
复制代码

错误七:忽略多重集成和方法解析顺序

与大多数编程语言不同,Python 支持多重继承。这意味着,在具有继承的类中,方法和类变量是根据继承类时指定的顺序执行的。


初学者往往会忽略这个概念,尤其是当他们只使用单一继承时。


因此,在下面这段代码中,当调用类 C 的方法时,将使用超类 B 各自的方法:


>>> class A(object):...     def me(self):print("class A")>>> class B(A):...     def me(self):print("class B")class C(B, A):passc = C()c.me() # prints class B
复制代码


因此,Python 中继承类的顺序很重要,因为它是用来解析方法的。

总结

Python 使用起来似乎非常简单,但是人们很容易被来自其他编程语言的概念所困扰,这就会导致奇怪的错误和崩溃。我希望本文所列举的错误能够帮助你厘清概念,从而写出健壮的 Python 代码。


作者介绍:


Anupam Chugh,视技术和代码为毕生追求。拥有 200 万阅读量的作家,现为 iOS 开发者。


原文链接:


https://towardsdatascience.com/7-deadly-sins-python-developers-do-eb53d8a880


2020-10-28 14:392220
用户头像
刘燕 InfoQ高级技术编辑

发布了 1112 篇内容, 共 569.9 次阅读, 收获喜欢 1979 次。

关注

评论 1 条评论

发布
用户头像
代码缩进可以调整下
2020-10-29 10:57
回复
没有更多了
发现更多内容

在京东做技术是种什么体验?| 13位零售人告诉你答案

京东零售技术

保姆级离线 TiDB V8+ 解释

TiDB 社区干货传送门

8.x 实践

【Redis技术进阶之路】「原理分析系列开篇」探索事件驱动枚型与数据特久化原理实现(数据持久化的实现AOF)

码界西柚

数据库 redis redis持久化 aof Redis底层原理

使用DataWorks Notebook实现智能图片标注,给你的图片加个“注释”

阿里云大数据AI技术

大数据 数据分析 ETL 多模态 Dataworks

下一代产品的“双向奔赴”  鸿蒙版百度网盘发布多项领先AI能力

极客天地

这些搜索技巧你不会?

Immerse

电子签借贷真实吗?315报道引发的行业地震!电子签到底冤不冤?

易成研发中心

TiCDC 新架构 v9.0.0 使用实践

TiDB 社区干货传送门

TiCDC新架构

重塑家庭观影标准,海信激光电视探索X1斩获艾普兰奖

新消费日报

今日最新消息!黑龙江网络安全等级保护备案新规定,速看!

黑龙江陆陆信息测评部

深入探究小红书笔记详情页面数据采集接口​

tbapi

小红书笔记详情接口 小红书API

《汽车电机MES系统实战指南:打造柔性化智能产线的4大核心模块与3项关键技术突破》​

万界星空科技

mes 制造业工厂 电机MES 汽车电机 汽车电机mes

高性能存储SIG月度动态:erofs快照器合入containerd社区,ANCK支持virtio-blk直通

OpenAnolis小助手

操作系统 高性能存储 龙蜥社区 龙蜥社区SIG EROFS

Karmada v1.13 版本发布!新增应用优先级调度能力

华为云原生团队

云计算 容器 云原生

电子签高利贷实况解读:央视3·15乌龙曝光,电子签行业替高利贷买单

易成研发中心

Karmada v1.13 版本发布!新增应用优先级调度能力

华为云开发者联盟

容器 云原生 集群 Karmada

【2月13日 - 3月14日】TiCDC 新架构试用通道正式开启,全新升级,抢先体验,多重参与奖励等你拿!

TiDB 社区干货传送门

高性能网络SIG双月动态:加速 SMC eBPF 透明替换特性上游化进程,并与上游深度研讨新特性

OpenAnolis小助手

操作系统 龙蜥社区 smc 龙蜥SIG月报

重识 APO:DeepSeek 掀起可观性领域变革 | 龙蜥生态

OpenAnolis小助手

AI 系统运维 apo 龙蜥生态 DeepSeek

荣耀时刻!第二届开放原子大赛-OS Copilot 学习赛获奖名单新鲜出炉

OpenAnolis小助手

开源 操作系统 龙蜥社区 龙蜥赛事

TiDB × AI :DeepSeek 时代你需要什么样的数据基座

PingCAP

AI TiDB DeepSeek

探秘能源行业AI密码:云鼎科技用大模型实现了″四个转变″

Alter

《Operating System Concepts》阅读笔记:p449-p459

codists

操作系统

用 tcpdump 分析 Java 客户端的 prepare 行为

TiDB 社区干货传送门

性能调优 故障排查/诊断

数字化转型投入大、见效慢?中小企业该如何应对?

天津汇柏科技有限公司

数字化转型

多智能体强化学习的算力调度创新,让每一份算力都创造广告价值 | 京东零售技术实践

京东零售技术

“官方网站+公开课程”双赋能,鸿蒙游戏开发者服务焕新升级

最新动态

SysOM 可观测体系建设(一):万字长文解读低开销、高精度性能剖析工具livetrace

OpenAnolis小助手

AI 可观测性 SysOM 龙蜥系统运维联盟 livetrace

CST软件如何用天线远场计算Group delay延时

思茂信息

cst CST软件 CST Studio Suite

龙蜥社区第六届理事大会成功举行,共话技术创新与生态合作

OpenAnolis小助手

开源 龙蜥社区 OpenAnolis 龙蜥社区理事大会

龙蜥 2024 年度“最佳合作伙伴”揭晓!申威、AMD 等多家新晋贡献厂商实力登榜

OpenAnolis小助手

操作系统 龙蜥社区 OpenAnolis 龙蜥社区年度优秀贡献者

Python 开发人员常犯的这7个错误,可能是“致命”的_AI&大模型_Anupam Chugh_InfoQ精选文章