Python编程中的反模式
admin
2023-07-31 01:42:54
0

这篇文章收集了我在Python新手开发者写的代码中所见到的不规范但偶尔又很微妙的问题。本文的目的是为了帮助那些新手开发者渡过写出丑陋的Python代码的阶段。为了照顾目标读者,本文做了一些简化(例如:在讨论迭代器的时候忽略了生成器和强大的迭代工具itertools)。

对于那些新手开发者,总有一些使用反模式的理由,我已经尝试在可能的地方给出了这些理由。但通常这些反模式会造成代码缺乏可读性、更容易出bug且不符合Python的代码风格。如果你想要寻找更多的相关介绍资料,我极力推荐The Python Tutorial或Dive into Python。

迭代

  • range的使用

Python编程新手喜欢使用range来实现简单的迭代,在迭代器的长度范围内来获取迭代器中的每一个元素:

12 for i in range(len(alist)):    print alist[i]

应该牢记:range并不是为了实现序列简单的迭代。相比那些用数字定义的for循环,虽然用range实现的for循环显得很自然,但是用在序列的迭代上却容易出bug,而且不如直接构造迭代器看上去清晰:

12 for item in alist:    print item

range的滥用容易造成意外的大小差一(off-by-one)错误,这通常是由于编程新手忘记了range生成的对象包括range的第一个参数而不包括第二个,类似于java中的substring和其他众多这种类型的函数。那些认为没有超出序列结尾的编程新手将会制造出bug:

1234 # 迭代整个序列错误的方法alist = [\’her\’, \’name\’, \’is\’, \’rio\’]for i in range(0, len(alist) 1): # 大小差一(Off by one)!    print i, alist[i]

不恰当地使用range的常见理由:
1. 需要在循环中使用索引。这并不是一个合理的理由,可以用以下方式代替使用索引:

12 for index, value in enumerate(alist):    print index, value

2. 需要同时迭代两个循环,用同一个索引来获取两个值。这种情况下,可以用zip来实现:

12 for word, number in zip(words, numbers):    print word, number

3. 需要迭代序列的一部分。在这种情况下,仅需要迭代序列切片就可以实现,注意添加必要的注释注明用意:

12 for word in words[1:]: # 不包括第一个元素    print word

有一个例外:当你迭代一个很大的序列时,切片操作引起的开销就比较大。如果序列只有10个元素,就没有什么问题;但是如果有1000万个元素时,或者在一个性能敏感的内循环中进行切片操作时,开销就变得非常重要了。这种情况下可以考虑使用xrange代替range [1]。

在用来迭代序列之外,range的一个重要用法是当你真正想要生成一个数字序列而不是用来生成索引:

123 # Print foo(x) for 0<=x<5for x in range(5):    print foo(x)

  • 正确使用列表解析

如果你有像这样的一个循环:

12345 # An ugly, slow way to build a listwords = [\’her\’, \’name\’, \’is\’, \’rio\’]alist = []for word in words:    alist.append(foo(word))

你可以使用列表解析来重写:

这篇文章收集了我在Python新手开发者写的代码中所见到的不规范但偶尔又很微妙的问题。本文的目的是为了帮助那些新手开发者渡过写出丑陋的Python代码的阶段。为了照顾目标读者,本文做了一些简化(例如:在讨论迭代器的时候忽略了生成器和强大的迭代工具itertools)。

对于那些新手开发者,总有一些使用反模式的理由,我已经尝试在可能的地方给出了这些理由。但通常这些反模式会造成代码缺乏可读性、更容易出bug且不符合Python的代码风格。如果你想要寻找更多的相关介绍资料,我极力推荐The Python Tutorial或Dive into Python。

迭代

  • range的使用

Python编程新手喜欢使用range来实现简单的迭代,在迭代器的长度范围内来获取迭代器中的每一个元素:

12 for i in range(len(alist)):    print alist[i]

应该牢记:range并不是为了实现序列简单的迭代。相比那些用数字定义的for循环,虽然用range实现的for循环显得很自然,但是用在序列的迭代上却容易出bug,而且不如直接构造迭代器看上去清晰:

12 for item in alist:    print item

range的滥用容易造成意外的大小差一(off-by-one)错误,这通常是由于编程新手忘记了range生成的对象包括range的第一个参数而不包括第二个,类似于java中的substring和其他众多这种类型的函数。那些认为没有超出序列结尾的编程新手将会制造出bug:

1234 # 迭代整个序列错误的方法alist = [\’her\’, \’name\’, \’is\’, \’rio\’]for i in range(0, len(alist) 1): # 大小差一(Off by one)!    print i, alist[i]

不恰当地使用range的常见理由:
1. 需要在循环中使用索引。这并不是一个合理的理由,可以用以下方式代替使用索引:

12 for index, value in enumerate(alist):    print index, value

2. 需要同时迭代两个循环,用同一个索引来获取两个值。这种情况下,可以用zip来实现:

12 for word, number in zip(words, numbers):    print word, number

3. 需要迭代序列的一部分。在这种情况下,仅需要迭代序列切片就可以实现,注意添加必要的注释注明用意:

12 for word in words[1:]: # 不包括第一个元素    print word

有一个例外:当你迭代一个很大的序列时,切片操作引起的开销就比较大。如果序列只有10个元素,就没有什么问题;但是如果有1000万个元素时,或者在一个性能敏感的内循环中进行切片操作时,开销就变得非常重要了。这种情况下可以考虑使用xrange代替range [1]。

在用来迭代序列之外,range的一个重要用法是当你真正想要生成一个数字序列而不是用来生成索引:

123 # Print foo(x) for 0<=x<5for x in range(5):    print foo(x)

  • 正确使用列表解析

如果你有像这样的一个循环:

12345 # An ugly, slow way to build a listwords = [\’her\’, \’name\’, \’is\’, \’rio\’]alist = []for word in words:    alist.append(foo(word))

你可以使用列表解析来重写:

相关内容

热门资讯

Mobi、epub格式电子书如... 在wps里全局设置里有一个文件关联,打开,勾选电子书文件选项就可以了。
定时清理删除C:\Progra... C:\Program Files (x86)下面很多scoped_dir开头的文件夹 写个批处理 定...
scoped_dir32_70... 一台虚拟机C盘总是莫名奇妙的空间用完,导致很多软件没法再运行。经过仔细检查发现是C:\Program...
500 行 Python 代码... 语法分析器描述了一个句子的语法结构,用来帮助其他的应用进行推理。自然语言引入了很多意外的歧义,以我们...
小程序支付时提示:appid和... [Q]小程序支付时提示:appid和mch_id不匹配 [A]小程序和微信支付没有进行关联,访问“小...
pycparser 是一个用... `pycparser` 是一个用 Python 编写的 C 语言解析器。它可以用来解析 C 代码并构...
微信小程序使用slider实现... 众所周知哈,微信小程序里面的音频播放是没有进度条的,但最近有个项目呢,客户要求音频要有进度条控制,所...
65536是2的几次方 计算2... 65536是2的16次方:65536=2⁶ 65536是256的2次方:65536=256 6553...
Apache Doris 2.... 亲爱的社区小伙伴们,我们很高兴地向大家宣布,Apache Doris 2.0.0 版本已于...
项目管理和工程管理的区别 项目管理 项目管理,顾名思义就是专注于开发和完成项目的管理,以实现目标并满足成功标准和项目要求。 工...