本文概述
PEP-8或Python增强建议提供了一些关键点, 你可以使用这些关键点来使代码更加有条理和可读性。正如Python创造者Guido Van Rossum所说:
读取代码比编写代码要频繁得多。
在本文中, 你将开始通过一些代码示例来探索PEP-8!你将涵盖以下主题:
- 首先, 你将了解PEP-8, 它是什么以及为什么需要它。
- 接下来, 你将解决缩进, 这是程序员中的热门话题。你应该使用制表符还是空格?你将在本节中找到分析器。
- 你可能不希望如此, 但是有关于最大行长的准则;
- 此外, 还提出了一种处理空白行的方法。
- 接下来, 表达式和语句中的空格是初学者也可以轻松解决的问题;
- 什么是编码?使用Python时为什么需要编码? Python3的默认编码是什么?源代码行编码部分将解决所有这些问题。
- 你可能在编码时经常导入。本节将讨论诸如导入顺序, 绝对和相对导入以及通配符导入等主题。
- 文档对于跟踪应用程序的各个方面以及提高最终产品的整体质量至关重要。这里的评论必不可少!
- 你知道型号级别的邓德尔名称吗?这些在文档字符串中特别有用!
- 最后, 你还将了解有关命名约定的更多信息:你将发现如何使用函数名称, 通常使用哪种类型的命名样式, 等等。
- 你的代码是否符合PEP-8?绝对是你应该问自己的问题。这就是为什么最后一部分介绍了一些工具来帮助你检查代码以查看其是否符合本文所提供的准则以及此处未涵盖的更多内容的原因!
PEP-8简介
在过去的一年中, Python编程语言已经发展成为最受欢迎的编程语言之一。这种语言比大多数编程语言相对易于学习。它是一个多范式, 它具有许多开源模块, 这些模块增加了该语言的实用性, 并且在数据科学和Web开发社区中日益流行。
但是, 只有在知道如何用代码更好地表达时, 才能使用Python的好处。编写Python时要牢记一些目标, 当你输入import this时可以看到这些目标。
import this
The Zen of Python, by Tim Peters
Beautiful is better than ugly.
Explicit is better than implicit.
Simple is better than complex.
Complex is better than complicated.
Flat is better than nested.
Sparse is better than dense.
Readability counts.
Special cases aren't special enough to break the rules.
Although practicality beats purity.
Errors should never pass silently.
Unless explicitly silenced.
In the face of ambiguity, refuse the temptation to guess.
There should be one-- and preferably only one --obvious way to do it.
Although that way may not be obvious at first unless you're Dutch.
Now is better than never.
Although never is often better than *right* now.
If the implementation is hard to explain, it's a bad idea.
If the implementation is easy to explain, it may be a good idea.
Namespaces are one honking great idea -- let's do more of those!
以上是Python编程使用的20条原则。你还可以在上面的输出中看到”可读性计数”, 这是编写代码时的主要注意事项:其他程序员或数据科学家应该理解并应该对你的代码有所贡献, 以便它可以解决当前的任务。
以下各节将为你提供更多有关如何实现上述目标的见解!
缩进
使用Python进行编程时, 你一定会使用缩进。但是, 你应该小心使用它, 因为它可能导致语法错误。因此, 建议使用4个空格进行缩进。例如, 此语句使用4个缩进空格:
if True:
print("If works")
而且, 此带打印语句的for循环缩进了4个空格:
for element in range(0, 5):
print(element)
编写大表达式时, 最好使表达式垂直对齐。当你这样做时, 你将创建一个”悬挂缩进”。
以下是大表达式中的悬挂缩进的一些示例, 显示了如何使用它的一些变体:
-
值= square_of_numbers(num1, num2, num3, num4) -
def square_of_number(num1, num2, num3, num4):返回num1 ** 2, num2 ** 2, num3 ** 2, num4 ** 2 -
值= square_of_numbers(num1, num2, num3, num4) -
list_of_people = [” Rama”, ” John”, ” Shiva”] -
dict_of_people_ages = {” ram”:25, ” john”:29, ” shiva”:26}
每个使用Python或其他编程语言的开发人员都会在某个时候问他或她自己是否使用制表符或空格进行缩进的问题。制表符和空格之间的区别是社区中正在进行的讨论。例如查看本文。
通常, 空格是首选的缩进方式, 但是如果你发现某些Python脚本已经在使用制表符, 则应继续使用制表符进行缩进。否则, 你应该使用空格更改脚本中所有表达式的缩进。
请注意, Python 3不允许混合制表符和空格用于缩进。这就是为什么你应该选择两者之一并坚持下去!
最大线长
通常, 将Python代码中的行长设置为79个字符为好。
遵循此目标编号具有许多优势。其中几个是:
- 可以并排打开文件进行比较;
- 你无需水平滚动即可查看整个表达式, 从而提高了可读性和对代码的理解。
注释应具有72个字符的行长。在本教程后面的部分, 你将学到更多关于最常见的注释约定的信息!
最后, 取决于你是在小组工作还是遵循哪种编码约定和样式, 对于大多数开发人员来说, 可以从最大行长准则中转移出来是可以接受的。但是, 如果你正在制作或致力于一个开源项目, 则可能需要和/或需要遵守PEP-8设定的最大行长规则。
在使用+运算符时, 你可以更好地使用适当的换行符, 这使你的代码更易于理解:
你应该使用… | 你应该避免… |
---|---|
总计=(A + B + C) | 总计=(A + B + C) |
另外, 你还可以编写:
total = A
+ B
+ C
简而言之, 只要你保持一致, 就可以在二进制运算符之前或之后添加一个break。如果要编写新代码, 则应尝试遵循给出的最后一个选项, 即在二进制运算符之前添加一个分隔符。
空行
在Python脚本中, 顶级函数和类由两个空行分隔。类内的方法定义应由一个空行分隔。在以下示例中, 你可以清楚地看到这一点:
class SwapTestSuite(unittest.TestCase):
"""
Swap Operation Test Case
"""
def setUp(self):
self.a = 1
self.b = 2
def test_swap_operations(self):
instance = Swap(self.a, self.b)
value1, value2 =instance.get_swap_values()
self.assertEqual(self.a, value2)
self.assertEqual(self.b, value1)
class OddOrEvenTestSuite(unittest.TestCase):
"""
This is the Odd or Even Test case Suite
"""
def setUp(self):
self.value1 = 1
self.value2 = 2
def test_odd_even_operations(self):
instance1 = OddOrEven(self.value1)
instance2 = OddOrEven(self.value2)
message1 = instance1.get_odd_or_even()
message2 = instance2.get_odd_or_even()
self.assertEqual(message1, 'Odd')
self.assertEqual(message2, 'Even')
SwapTestSuite和OddOrEvenTestSuite类由两条空行分隔, 而方法定义(如.setUp()和.test_swap_operations())只有一条空行将它们分开。
表达式和语句中的空白
当你看到代码像下面的示例一样编写时, 应尽量避免使用空格:
你应该使用… | 你应该避免… |
---|---|
func(data, {pivot:4}) | func(数据, {枢轴:4}) |
索引=(0, ) | 索引=(0, ) |
如果x == 4:打印x, y; x, y = y, x | 如果x == 4:打印x, y; x, y = y, x |
spam(1) |
spam (1) |
dct [‘key’] = lst [index] | dct [‘key’] = lst [index] |
x = 1 y = 2 long_variable = 3 | x = 1 y = 2 long_variable = 3 |
ham [1:9], ham [1:9:3], ham [:9:3], ham [1 :: 3], ham [1:9:] ham [lower:upper], ham [lower:上边:], 火腿[下边::台阶]火腿[下边+偏移量:上边+偏移量]上限+偏移量] | ham [lower + offset:upper + offset] ham [1:9], ham [1:9], ham [1:9:3] ham [lower::upper] ham [:upper] |
i = i + 1提交+ = 1 x = x2-1 hypot2 = xx + yy c =(a + b)(a-b) | i = i + 1提交+ = 1 x = x 2-1 hypot2 = xx + y y c =(a + b)(a-b) |
def复杂(真实, imag = 0.0):返回魔术(r =真实, i = imag) | def complex(真实, imag = 0.0):返回魔术(r =真实, i = imag) |
def munge(输入:AnyStr):… def munge()-> AnyStr:… | def munge(输入:AnyStr):… def munge()-> PosInt:… |
def munge(sep:AnyStr = None):… def munge(input:AnyStr, sep:AnyStr = None, limit = 1000):… | def munge(输入:AnyStr =无):… def munge(输入:AnyStr, 极限= 1000):… |
如果foo ==’blah’:do_blah_thing()do_one()do_two()do_three() | 如果foo ==’blah’:do_blah_thing()do_one(); do_two(); do_three()或if foo ==’blah’:do_blah_thing()for lst中的x:total + = x而t <10:t = delay()或if foo ==’blah’:do_blah_thing()else:do_non_blah_thing( )试试:something()最后:cleanup()do_one(); do_two(); do_three(long, arguments, list, like, this)if foo ==’blah’:one();二();三() |
文件=(‘setup.cfg’, ) | FILES =’setup.cfg’, |
FILES = [‘setup.cfg’, ‘tox.ini’, ] initialize(FILES, error = True, ) | FILES = [‘setup.cfg’, ‘tox.ini’, ] initialize(FILES, error = True, ) |
这些示例摘自PEP-8。
源文件编码
计算机不能存储”字母”, “数字”, “图片”或其他任何内容;它只能存储和使用只能具有二进制值的位:yes或no, true或false, 1或0等等。这意味着”实际”位是有无电信号。你通常用1和0表示这种(缺乏)存在。
要使用位来表示除位之外的所有内容, 你需要一套规则。你需要使用编码方案或编码将一系列位转换为字母, 数字和图片等内容。编码方案的示例是ASCII, UTF-8等:
- 美国信息交换标准码(ASCII)是计算机和Internet上文本文件的最常见格式。在这种类型的文件中, 每个字母, 数字或特殊字符都用7位二进制数字(七个0或1s的字符串)表示。
- Unicode全球字符标准(简称Unicode)是用于”交换, 处理和显示现代世界各种语言的书面文本”的系统。简而言之, Unicode旨在适应世界上所有已知的书写系统。 Unicode当前采用三种不同的编码来表示Unicode字符集:UTF-8, UTF-16和UTF-32。
- UTF-16是一种可变长度的Unicode编码:代码点使用一个或两个16位代码单元进行编码。
- UTF-8是另一种Unicode变长编码, 使用一到四个8位字节。
- UTF-32是固定长度的编码, 每个Unicode代码点正好使用32位。
提示:如果你想进一步了解编码, 请查看这篇文章。
现在, 为什么这很重要?
你会发现字符串是Python中最常用的数据类型之一。如你所料, 有时会使用包含或完全由不属于标准ASCII字符集的字符组成的字符串。毕竟, 可能是你必须处理包含重音符号(例如á, ž, ç等)的文本。
现在, 在Python 3中, UTF-8是默认的源编码。但是, 对于那些使用Python 2的人来说, 你可能已经知道默认值是ASCII。
但是, 如果你的字符串包含非ASCII字符, 例如”Flügel”, 该怎么办?
当你在Python 2中引用该字符串时, 将得到以下内容:
>>> s
'Fl\xfcgel'
这看起来不像你的字符串!打印时会怎样?
>>> print(s)
Flügel
打印为你提供了分配给变量的值。非ASCII字符Œ已编码。这就是为什么在引用字符串时返回\ xfc的原因。要处理此问题, 可以使用.encode()和.decode()字符串方法。前者返回Unicode字符串的8位字符串版本, 以请求的编码方式编码, 而后者使用给定的编码解释该字符串。
进口货
在使用Python进行数据科学时, 通常会导入库和/或模块。你可能已经知道, 应该始终在脚本开始时导入库。
请注意, 如果你进行多次导入, 则应确保在一行上声明每个导入。
查看下表以更好地了解这一点:
你应该使用… | 你应该避免… |
---|---|
从配置导入设置或导入os import sys | 导入操作系统 |
此外, 在导入库时, 应考虑到需要遵守的顺序。通常, 你可以按照以下顺序进行:
- 标准库导入。
- 相关的第三方进口。
- 本地应用程序/库特定的导入。
绝对和相对进口
接下来, 很高兴知道绝对进口和相对进口之间的区别。通常, 绝对导入在Python中是首选, 因为它增加了可读性。但是, 随着应用程序变得越来越复杂, 你也可以继续使用相对导入。绝对不要使用隐式相对导入, 并且在Python 3中已将其删除。
但是这些绝对和相对进口是什么?
绝对导入是使用函数或类的绝对路径(以。分隔)的导入。例如,
import sklearn.linear_model.LogisticRegression
相对导入是相对于Python文件所在的当前位置的导入。如果你的项目结构正在增长, 则可以使用这种类型的导入, 因为这会使你的项目更具可读性。这意味着, 如果你具有如下所示的Python项目结构:
.
├── __init__.py
├── __init__.pyc
├── __pycache__
│ ├── __init__.cpython-35.pyc
│ ├── bubble_sort.cpython-35.pyc
│ ├── selection_sort.cpython-35.pyc
├── bubble_sort.py
├── heap_sort.py
├── insertion_sort.py
├── insertion_sort.pyc
├── merge_sort.py
├── merge_sort.pyc
├── quick_sort.py
├── radix_sort.py
├── selection_sort.py
├── selection_sort.pyc
├── shell_sort.py
├── tests
│ ├── test1.py
你可以使用相对导入来导入气泡排序算法BubbleSort, 该算法存储在test1的bubble_sort.py中。看起来像这样:
from ..bubble_sort import BubbleSort
如果你想了解有关绝对进口和相对进口的更多信息, 可以查看PEP 328。
通配符导入
最后, 你应该尝试避免通配符导入, 因为通配符不会增加可读性。你无法查看模块中正在使用哪些类, 方法或变量, 例如:
from scikit import *
注释
注释用于Python中的代码内文档。它们增加了对代码的理解。你可以使用许多工具来为自己的模块生成文档, 例如注释和文档字符串。注释应该更加冗长, 以便当某人阅读该代码时, 该人将对该代码以及如何将其与其他代码一起使用有适当的了解。
注释以#符号开头。在井号标签之后编写的任何内容都不会由解释器执行。例如, 以下代码块将仅返回”这是Python注释”。
# This is a Python single line comment
print("This is a Python comment")
请记住:在上一节中, 你读到注释应具有72个字符的行长!
话虽这么说, 但有三种类型的评论:
- 你可以使用块注释来解释更复杂或不熟悉的代码。这些通常是较长形式的注释, 它们适用于随后的部分或全部代码。块注释的缩进程度与代码相同。块注释的每一行都以#号和一个空格开头。如果需要使用多个段落, 则应将其用包含单个#的行分隔。
请看以下摘自scikit-learn库的摘录, 以了解这些注释是什么样的:
if Gram is None or Gram is False:
Gram = None
if copy_X:
# force copy. setting the array to be fortran-ordered
# speeds up the calculation of the (partial) Gram matrix
# and allows to easily swap columns
X = X.copy('F')
- 即使应该在解释代码的某些部分时有效, 也应谨慎使用内联注释。它们还可以帮助你记住特定代码行的含义, 或者在与不熟悉代码各个方面的人员进行协作时可以派上用场。你可以在代码的后面, 在语句的同一行上使用内联注释。这些注释也以#和单个空格开头。
例如:
counter = 0 # initialize the counter
- 你可以在公共模块, 文件, 类和方法的开始处编写文档字符串或文档字符串。这些类型的注释以”””开头, 以”””结尾:
"""
This module is intended to provide functions for scientific computing
"""
模块级dunder名称
既然你已经阅读了什么文档字符串, 那么你也应该了解Module Level dunder, 或者带有两个前导和两个尾随下划线的名称在Python中非常有效。这些是Python定义的特殊名称, 因此它不会与用户定义的函数或名称冲突。有关更多信息, 你可以查看本文。
诸如(__all __, __ author __, __ version__)之类的模块级dunder应该放置在模块主文档字符串中, 并且应位于所有import语句之前。你应该在__future__导入之前定义任何其他代码, 但文档字符串除外:
"""
Algos module consists of all the basic algorithms and their implementation
"""
from __future__ import print
__all__ = ['searching', 'sorting']
__version__ = '0.0.1'
__author__ = 'Chitrank Dixit'
import os
import sys
提示:请查看以下用于编写文档字符串的约定。
命名约定
当你使用Python进行编程时, 你肯定会使用命名约定, 即一组用于选择字符序列的规则, 这些规则应用于标识符, 这些标识符表示源代码和文档中的变量, 类型, 函数和其他实体。
如果不确定哪种命名方式, 请考虑以下几种:
- b或单个小写字母;
- B或单个大写字母;
- 小写
- 大写
- lower_case_with_underscores
- UPPER_CASE_WITH_UNDERSCORES
- 大写单词, 也称为CapWords, CamelCase或StudlyCaps。
- 混合情况
- 大写的单词_带_下划线
- _single_leading_underscore:”内部使用”指标较弱。例如, 从M import *不会导入名称以下划线开头的对象。
- single_trailing_underscore_:按惯例使用, 以避免与Python关键字发生冲突, 例如Tkinter.Toplevel(master, class _ =’ClassName’)
- __double_leading_underscore:命名类属性时, 调用名称修饰(在类FooBar中, __boo变为_FooBar__boo)。
- __double_leading_and_trailing_underscore__:存在于用户控制的命名空间中的”魔术”对象或属性。例如, __ init __, __ import__或__file__。你永远都不要发明这样的名称, 而只能按照说明使用它们。
一般命名约定
下表显示了有关如何命名标识符的一些一般准则:
识别 | 惯例 |
---|---|
模组 | 小写 |
类 | 字词 |
函数 | 小写 |
方法 | 小写 |
类型变量 | 字词 |
常量 | 大写 |
包 | 小写 |
- 不要将’l’, ‘O’或’I’用作单个变量名:在某些字体中, 这些字符看起来与零(0)和(1)相似。
- 通常, 最好使用短名称。在某些情况下, 你可以使用下划线来提高可读性。
如果你想进一步了解通用命名约定的例外情况, 请查看本文。
你的代码是否符合PEP-8?
在学习了更多关于PEP-8的知识之后, 你可能想知道如何检查你的代码是否确实符合这些准则(以及本教程未涵盖的更多内容!)。
除了亲自检查PEP-8并对其进行更多了解之外, 你绝对应该考虑研究便捷的pep8模块, coala软件包以及下一部分中介绍的其他替代产品!
Python pep8软件包
pep8软件包旨在在你的代码中搜索PEP-8不兼容, 并建议你进行一些更改以使你的代码遵循PEP-8。
你可以使用pip安装pep8模块。
$ pip install pep8
例如,
$ pep8 --first optparse.py
optparse.py:69:11: E401 multiple imports on one line
optparse.py:77:1: E302 expected 2 blank lines, found 1
optparse.py:88:5: E301 expected 1 blank line, found 0
optparse.py:222:34: W602 deprecated form of raising exception
optparse.py:347:31: E211 whitespace before '('
optparse.py:357:17: E201 whitespace after '{'
optparse.py:472:29: E221 multiple spaces before operator
optparse.py:544:21: W601 .has_key() is deprecated, use 'in'
你也可以使用–show-source参数查看发现不兼容的源代码:
$ pep8 --show-source --show-pep8 testsuite/E40.py
testsuite/E40.py:2:10: E401 multiple imports on one line
import os, sys
^
Imports should usually be on separate lines.
Okay: import os\nimport sys
E401: import sys, os
或者, 你可以通过添加–statistics来显示发现每个错误的频率:
$ pep8 --statistics -qq Python-2.5/Lib
232 E201 whitespace after '['
599 E202 whitespace before ')'
631 E203 whitespace before ', '
842 E211 whitespace before '('
2531 E221 multiple spaces before operator
4473 E301 expected 1 blank line, found 0
4006 E302 expected 2 blank lines, found 1
165 E303 too many blank lines (4)
325 E401 multiple imports on one line
3615 E501 line too long (82 characters)
612 W601 .has_key() is deprecated, use 'in'
1188 W602 deprecated form of raising exception
提示:还要确保签出其他模块, 例如flake8, autopep8或pylint!
使用Coala分析你的代码
Coala提供了所有语言的整理和修复功能, 但是你在这里更加关注Python编程, 可以使用pip安装Coala:
$ pip3 install coala-bears
在上面的代码块中, 你看到你实际上安装了Coala-bears:Bears是扩展你的Coala功能并因语言而异的插件或简单模块。在这种情况下, 你要使用pep8bear, 它可以找到PEP-8不兼容的代码并对其进行修复。你绝对应该考虑使用它来检查你的Python代码。
$ coala -S python.bears=PEP8Bear python.files=\*\*/\*.py \
python.default_actions=PEP8Bear:ApplyPatchAction --save
# other output ...
Executing section python...
[INFO][11:03:37] Applied 'ApplyPatchAction' for 'PEP8Bear'.
[INFO][11:03:37] Applied 'ApplyPatchAction' for 'PEP8Bear'.
pep8online:在线检查你的Python代码
除了方便的pep8模块和Coala软件包之外, 你还可以通过转到pep8online检查你的Python代码是否符合PEP-8。该站点有一个在线编辑器, 你可以粘贴代码, 然后单击”检查代码”按钮!结果, 你将获得有关需要改进的一些反馈。好用!
总结
使用Python时, 由于急于快速发布功能, 有时你并不关心代码质量。但是, 本教程中描述的实践以及此处未介绍的更多实践应该成为你的开发, 测试, 部署过程的一部分。这使从事该项目的每个人都可以理解, 并且大多数情况下, 无需启动调试器就可以对代码进行更改, 而无需深入了解和理解代码。如果你正在从事一个开源项目, 那么你的贡献者会发现PEP-8非常幸福, 并且因为这是通用标准, 所以会更好地理解你的代码, 每个Python开发人员都遵循这一点。
既然你已经完成了本教程, 那么亲自检查PEP-8是一个很好的主意!还有更多发现。
如果你还有其他有关如何遵守PEP-8的技巧, 或者你认为我们在本文中未提及重要内容, 请随时告诉我们@srcmini。
评论前必须登录!
注册