Python 作为最受初学者欢迎的编程语言之一, 是世界各地学校中被最广泛教授的语言.
然而, 学习 Python 并非易事. 首先, 需要找到最佳的在线学习途径, 而这本身就很困难. 市面上有成千上万种不同的 Python 课程和辅导, 都声称自己是最好的.
的确, 仅凭练习是不够完美的, 但完美的练习却是完美的. 这意味着, 需确保自己始终遵循着最佳编码实践(对代码进行注释, 使用正确句法等), 反之, 则可能会养成一些不良习惯, 影响您在编码行业的未来发展.
“通用规范提供了所有的可维护性,清晰性,一致性,也为良好的编程习惯奠定基础。它不能做的就是违背您的意愿,坚持让您学习它。这就是 Python!”
— Tim Peters 发表于 comp.lang.python, 2001–06–16
|
在本篇文章中, 我将分享十个帮助您快速有效地用 Python 进行编码的技巧.
1. 可读性的重要性
程序必须为了人们能够读懂而编写, 其次使机器能够执行.
Hal Abelson(https://www.azquotes.com/author/38260-Hal_Abelson)
首先, 遵循编程规范, 使程序易于阅读. 编程规范是经验丰富的程序员在编写其代码时所遵循的. 除忽略这些规范外, 没有任何其他方式可以更快地证明您是位 "新手". 其中一些规范特定于 Python; 其他则可由计算机程序员用于所有语言中.
从本质上讲, 可读性一种特征, 决定着他人理解您代码某些部分的难易程度(而并非您本人!).
举例来说, 我曾经不习惯用垂直对齐方式来编写代码, 也不习惯用起始分隔符对齐函数参数.
- # No, to avoid:
- func = long_function_name(var_one, var_two,
- var_three, var_four)#Yes,
- func = long_function_name(var_one, var_two,
- var_three, var_four)
查看 Python 代码样式指南 (https://www.python.org/dev/peps/pep-0008/) 中的其他示例, 并确定哪个示例看起来最佳.
我们经常做的另一件重要事情是效仿曾看过或写过的程序, 这也是为何接触可读性强的程序对于编程学习十分重要的原因.
2. 避免无用条件
通常, 一串 if & elif & .... & else 长条件是代码需要重构的标志. 这些条件使您的代码冗长, 且十分难于解释. 有时这些代码可以被很容易地替换, 例如, 我曾经常这样做过:
- def f():
- if condition:
- return True
- else:
- return False
这真是愚蠢! 该函数返回一个布尔值, 那么为什么还要首先使用 if 块呢? 正确的做法是:
- def f():
- return condition
在一项 Hackerrank 挑战中, 参赛者需要编写一个函数来确定给定的年份是否为闰年. 在公历中, 须考虑三个标准来确定闰年:
该年份可被 4 整除, 为闰年, 除非:
该年份同样可被 100 整除, 不是闰年, 除非:
该年份也可被 400 整除. 为闰年
在这项挑战中, 不要考虑 ifs 和 elses 条件, 仅做如下即可:
- def is_leap(year):
- return year % 4 == 0 and (year % 400 == 0 or year % 100 != 0)
3. 适当使用空白
切勿混淆键盘制表定位键与空格键
函数间进行一次换行
等级间进行两次换行
在程序库, 列表, 元组, 自变量列表中的自变量的 "," 后输入空格, 以及在程序库的 ":" 后输入空格.
在分配和比较前后放置空格(列表中的自变量除外)
括号前后或参数列表前无空格
- def function(key, value=0):
- """Return a dictionary and a list..."""
- d = {key: value}
- l = [key, value]
- return d, l
4. 文档字符串和注释
文档字符串 = 如何使用代
注释 = 为何代码能 (合理) 执行和如何执行
文档字符串解释了如何使用代码:
解释函数用途, 即使对您而言, 这个用途十分明显. 但以后, 其用途对他人来说, 不一定同样明显.
描述期望参数, 返回值及例外情况.
如果该类函数与单个 Caller 紧密耦合, 请提及调用函数.
这些注释向代码维护人员说明维护需求. 下面的示例也包括给自己的注释, 如:
- # !!! BUG: ...
- # !!! FIX: This is a hack
- # ??? Why is this here?
编写良好的文档字符串和注释是您的责任, 因此请始终使它们保持最新! 在进行更改时, 请确保注释和文档字符串与代码一致.
您将在 "文档字符串惯例"
(https://www.python.org/dev/peps/pep-0257/)中找到专门用于文档字符串的详细 PEP
5. 变量和分配
在其他编程语言中:
c = a
a = b
b = c
在 Python 中, 最好将分配项放入一个代码行中:
b, aa = a, b
您可能已经看到代码, 但您知道它如何执行吗?
逗号是构造元组的句法.
在右侧创建一个元组(元组包).
元组是左侧的目标(元组拆包).
其他示例:
- result = ''
- for s in colors:
- result += s
在结构化数据循环中很有用(已保留上述变量名):
result = ' '.join(colors)
也可以采取相反的方式, 只需确保左右具有相同的结构即可:
- >>> jan, (gname, gtitle, gphone) = people
- >>> gname
- 'German'
- >>> gtitle
- 'GBT'
- >>> gphone
- 'unlisted'
- >>> jan
- ['Jan', 'Gomez', '+1-888-222-1546']
6. 列表拼接 & 合并
首先从字符串列表开始:
colors = ['red', 'blue', 'green', 'yellow']
我们想将这些字符串连接在一起以创建一条长链. 特别是当子字符串的数量很大时, 请避免这样做:
- result = ''
- for s in colors:
- result += s
这样做非常慢. 且占用大量内存和性能. 总和将累加, 存储, 然后继续进行每个中间步骤.
取而代之, 执行以下操作:
- colors = ['red', 'blue', 'green', 'yellow']
- print ('Choose', ','.join(colors[:-1]), \
- 'or', colors[-1])>> Choose red, blue, green or yellow
join()函数可一次完成整个副本. 当仅处理几个字符串时, 它与其他函数没有什么区别. 却能使您养成使用最佳函数构建长链的习惯, 因为面对成百上千的字符串, 使用 join()函数的确大有不同.
下面是使用 join()函数的一些技巧. 如果想使用空格作为分隔符:
- # Do this : # And not this :
- if x: if x == True:
- pass pass# Do this : # And not this :
- if items: if len(items) != 0:
- pass pass# and especially not that :
- if items != []:
- pass
或逗号和空格:
result = ','.join(colors)
为了使句子语法正确, 除最后一个值之外的每个值之间都使用逗号 (人们更喜欢使用 "或"). 拆分列表的语法将完成其余工作.[:-1] 返回除最后一个值外的所有内容, 我们可以将其与逗号连接.
- colors = ['red', 'blue', 'green', 'yellow']
- print ('Choose', ','.join(colors[:-1]), \
- 'or', colors[-1])>> Choose red, blue, green or yellow
7. 测试真实条件
就布尔值而言, 利用 Python 既简洁又快速:
- # Do this : # And not this :
- if x: if x == True:
- pass pass# Do this : # And not this :
- if items: if len(items) != 0:
- pass pass# and especially not that :
- if items != []:
- pass
8. 尽可能使用枚举函数
枚举函数获取一个列表并返回数对(指数, 数项):
- items = ['zero', 'one', 'two', 'three']
- >>> print list(enumerate(items))
- [(0, 'zero'), (1, 'one'), (2, 'two'), (3, 'three')]
使用列表显示结果是必要的, 因为枚举函数是一种惰性函数, 仅在要求时才一次生成一个数项(一对).for 循环需要这种机制. 一次 Print 函数不会得到任何结果, 但必须拥有要显示的完整消息. 因此, 在使用 Print 函数之前, 我们应自动将生成器转换为列表.
因此, 使用下面的循环效果更佳:
- >>> [(x, y) for x in (1, 2, 3, 4) if x % 2 == 0
- for y in ['a', 'b'] if y == 'b']
- [(2, 'b'), (4, 'b')]
使用枚举函数的版本比其他两个版本更短, 更简单. 以上为表明枚举函数返回迭代器的示例(生成器是迭代器的一种).
9. 列表推导式
使用 for 和 if 的传统方式:
让我们对小于 100 的数字平方求和:
- # With a loop :
- total = 0
- for num in range(1, 101):
- total += num * num
使用列表推导式:
new_list = [fn(item) for item in a_list if condition(item)]
列表推导式清晰直接. 在同一个列表推导式中, 可以包含几个 for 循环和 if 条件, 但如果超过两个或三个, 或条件十分复杂, 我建议您使用普通的 for 循环.
例如, 从 0 至 9 的二次幂列表:
- >>> [n ** 2 for n in range(10)]
- [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
上个列表中的奇数列表:
- >>> [n ** 2 for n in range(10) if n % 2]
- [1, 9, 25, 49, 81]
更多示例:
- >>> [(x, y) for x in (1, 2, 3, 4) if x % 2 == 0
- for y in ['a', 'b'] if y == 'b']
- [(2, 'b'), (4, 'b')]
10. 生成器表达式
让我们对小于 100 的数字平方求和:
让我们对小于 100 的数字平方求和:
- # With a loop :
- total = 0
- for num in range(1, 101):
- total += num * num
还可以使用 sum 函数, 通过建立正确的序列来为我们更快地完成工作.
- # With a list comprehension :
- total = sum([num * num for num in range(1, 101)])# With a generator expression :
- total = sum(num * num for num in xrange(1, 101))
生成器表达式类似于列表推导式, 只是在计算时属于懒惰型. 列表推导式一次计算整个结果, 然后将其存储在列表中. 必要时, 生成器表达式一次计算一个值. 当序列很长并且生成的列表只是中间步骤而不是最终结果时, 生成器表达式特别有用.
例如, 如果我们必须对数十亿个整数的平方求和, 使用列表推导会达到内存的饱和, 但使用生成器表达式不会有任何问题. 尽管这需要一段时间!
total = sum(num * num for num in range(1, 1000000000))
二者在语法上的差异是列表推导式带有方括号, 而生成器表达式则没有. 生成器表达式有时需要括号, 因此您应始终使用它们.
简而言之:
当期望结果为列表时使用列表推导式.
当列表仅为中间结果时使用生成器表达式.
来源: http://developer.51cto.com/art/202003/613463.htm