如何编写简洁美观的Python代码

做者|ANIRUDDHA BHANDARI
编译|VK
来源|Analytics Vidhyapython

概述

  • Python风格教程将使你可以编写整洁漂亮的Python代码
  • 在这个风格教程中学习不一样的Python约定和Python编程的其余细微差异

介绍

你有没有遇到过一段写得很糟糕的Python代码?我知道大家不少人都会点头的。程序员

编写代码是数据科学家或分析师角色的一部分。另外一方面,编写漂亮整洁的Python代码彻底是另外一回事。做为一个精通分析或数据科学领域(甚至软件开发)的程序员,这极可能会改变你的形象。编程

那么,咱们如何编写这种所谓漂亮的Python代码呢?bash

欢迎学习Python风格教程app

数据科学和分析领域的许多人来自非编程背景。咱们先从学习编程的基础知识开始,接着理解机器学习背后的理论,而后开始征服数据集。机器学习

在这个过程当中,咱们常常不练习核心编程,也不注意编程惯例。ide

这就是本Python风格教程将要解决的问题。咱们将回顾PEP-8文档中描述的Python编程约定,你将成为一个更好的程序员!函数

目录

  • 为何这个Python风格的教程对数据科学很重要?
  • 什么是PEP8?
  • 了解Python命名约定
  • Python风格教程的代码布局
  • 熟悉正确的Python注释
  • Python代码中的空格
  • Python的通常编程建议
  • 自动格式化Python代码

为何这个Python风格的教程对数据科学很重要

有几个缘由使格式化成为编程的一个重要方面,尤为是对于数据科学项目:布局

  • 可读性

好的代码格式将不可避免地提升代码的可读性。这不只会使你的代码更有条理,并且会使读者更容易理解程序中正在发生的事情。若是你的程序运行了数千行,这将特别有用。学习

你会有不少的数据帧、列表、函数、绘图等,若是不遵循正确的格式准则,你甚至会很容易失去对本身代码的跟踪!

  • 协做

若是你在一个团队项目上合做,大多数数据科学家都会这样作,那么好的格式化就成了一项必不可少的任务。

这样能够确保代码被正确理解而不产生任何麻烦。此外,遵循一个通用的格式模式能够在整个项目生命周期中保持程序的一致性。

  • Bug修复

当你须要修复程序中的错误时,拥有一个格式良好的代码也将有助于你。错误的缩进、不恰当的命名等都很容易使调试成为一场噩梦!

所以,最好是以正确的编写风格来开始编写你的程序!

考虑到这一点,让咱们快速概述一下本文将介绍的PEP-8样式教程!

什么是PEP-8

PEP-8或Python加强建议是Python编程的风格教程。它是由吉多·范罗森、巴里·华沙和尼克·科格兰写的。它描述了编写漂亮且可读的Python代码的规则。

遵循PEP-8的编码风格将确保Python代码的一致性,从而使其余读者、贡献者或你本身更容易理解代码。

本文介绍了PEP-8指导原则中最重要的方面,如如何命名Python对象、如何构造代码、什么时候包含注释和空格,最后是一些很重要但很容易被大多数Python程序员忽略的通常编程建议。

让咱们学习编写更好的代码!

官方PEP-8文档能够在这里找到。

https://www.python.org/dev/pe...

了解Python命名约定

莎士比亚有句名言:“名字里有什么?”. 若是他当时遇到了一个程序员,他会很快获得一个答复——“不少!”.

是的,当你编写一段代码时,你为变量、函数等选择的名称对代码的可理解性有很大的影响。看看下面的代码:

# 函数 1
def func(x):
   a = x.split()[0]
   b = x.split()[1]
   return a, b
print(func('Analytics Vidhya'))

# 函数 2
def name_split(full_name):
   first_name = full_name.split()[0]
   last_name = full_name.split()[1]
   return first_name, last_name
print(name_split('Analytics Vidhya'))
# 输出
('Analytics', 'Vidhya')
('Analytics', 'Vidhya')

这两个函数的做用是同样的,可是后者提供了一个更好的直觉让咱们知道发生了什么,即便没有任何注释!

这就是为何选择正确的名称和遵循正确的命名约定能够在编写程序时能够产生巨大的不一样。话虽如此,让咱们看看如何在Python中命名对象!

开头命名

这些技巧能够应用于命名任何实体,而且应该严格遵照。

  • 遵循相同的模式
thisVariable, ThatVariable, some_other_variable, BIG_NO
  • 避免使用长名字,同时也不要太节俭的名字
this_could_be_a_bad_name = “Avoid this!”
t = “This isn\’t good either”
  • 使用合理和描述性的名称。这将有助于之后你记住代码的用途
X = “My Name”  # 防止这个
full_name = “My Name”  # 这个更好
  • 避免使用以数字开头的名字
1_name = “This is bad!”
  • 避免使用特殊字符,如@、!、#、$等
phone_ # 很差

变量命名

  • 变量名应始终为小写
blog = "Analytics Vidhya"
  • 对于较长的变量名,请使用下划线分隔单词。这提升了可读性
awesome_blog = "Analytics Vidhya"
  • 尽可能不要使用单字符变量名,如“I”(大写I字母)、“O”(大写O字母)、“l”(小写字母l)。它们与数字1和0没法区分。看看:
O = 0 + l + I + 1
  • 全局变量的命名遵循相同的约定

函数命名

  • 遵循小写和下划线命名约定
  • 使用富有表现力的名字
# 避免
def con():
    ...
# 这个更好
def connect():
    ...
  • 若是函数参数名与关键字冲突,请使用尾随下划线而不是缩写。例如,将break转换为break_u而不是brk
# 避免名称冲突
def break_time(break_):
    print(“Your break time is”, break_,”long”)

类名命名

  • 遵循CapWord(或camelCase或StudlyCaps)命名约定。每一个单词以大写字母开头,单词之间不要加下划线
# 遵循CapWord
class MySampleClass:
    pass
  • 若是类包含具备相同属性名的子类,请考虑向类属性添加双下划线

这将确保类Person中的属性__age被访问为 _Person__age。这是Python的名称混乱,它确保没有名称冲突

class Person:
    def __init__(self):
        self.__age = 18

obj = Person() 
obj.__age  # 错误
obj._Person__age  # 正确
  • 对异常类使用后缀“Error”
class CustomError(Exception):
    “””自定义异常类“””

类方法命名

  • 实例方法(不附加字符串的基本类方法)的第一个参数应始终为self。它指向调用对象
  • 类方法的第一个参数应始终为cls。这指向类,而不是对象实例
class SampleClass:
    def instance_method(self, del_):
        print(“Instance method”)

    @classmethod
    def class_method(cls):
        print(“Class method”)

包和模块命名

  • 尽可能使名字简短明了
  • 应遵循小写命名约定
  • 对于长模块名称,首选下划线
  • 避免包名称使用下划线
testpackage # 包名称
sample_module.py # 模块名称

常量命名

  • 常量一般在模块中声明和赋值
  • 常量名称应所有为大写字母
  • 对较长的名称使用下划线
# 下列常量变量在global.py模块
PI = 3.14
GRAVITY = 9.8
SPEED_OF_Light = 3*10**8

Python风格教程的代码布局

如今你已经知道了如何在Python中命名实体,下一个问题应该是如何用Python构造代码!

老实说,这是很是重要的,由于若是没有适当的结构,你的代码可能会出问题,对任何评审人员来讲都是最大的障碍。

因此,不用再多费吹灰之力,让咱们来了解一下Python中代码布局的基础知识吧!

缩进

它是代码布局中最重要的一个方面,在Python中起着相当重要的做用。缩进告诉代码块中要包含哪些代码行以供执行。缺乏缩进多是一个严重的错误。

缩进肯定代码语句属于哪一个代码块。想象一下,尝试编写一个嵌套的for循环代码。在各自的循环以外编写一行代码可能不会给你带来语法错误,但你最终确定会遇到一个逻辑错误,这可能会在调试方面耗费时间。

遵循下面提到的缩进风格,以得到一致的Python脚本风格。

  • 始终遵循4空格缩进规则
# 示例
if value<0:
    print(“negative value”)

# 另外一个例子
for i in range(5):
    print(“Follow this rule religiously!”)
  • 建议用空格代替制表符

建议用空格代替制表符。可是当代码已经用制表符缩进时,可使用制表符。

if True:
    print('4 spaces of indentation used!')
  • 将大型表达式拆分红几行

处理这种状况有几种方法。一种方法是将后续语句与起始分隔符对齐。

# 与起始分隔符对齐。
def name_split(first_name,
               middle_name,
               last_name)

# 另外一个例子。
ans = solution(value_one, value_two,
               value_three, value_four)

第二种方法是使用4个空格的缩进规则。这将须要额外的缩进级别来区分参数和块内其余代码。

# 利用额外的缩进。
def name_split(
        first_name,
        middle_name,
        last_name):
    print(first_name, middle_name, last_name)

最后,你甚至可使用“悬挂缩进”。悬挂缩进在Python上下文中是指包含圆括号的行以开括号结束的文本样式,后面的行缩进,直到括号结束。

# 悬挂缩进
ans = solution(
    value_one, value_two,
    value_three, value_four)
  • 缩进if语句多是一个问题

带有多个条件的if语句天然包含4个空格。如你所见,这多是个问题。随后的行也将缩进,而且没法区分if语句和它执行的代码块。如今,咱们该怎么办?

好吧,咱们有几种方法能够绕过它:

# 这是个问题。
if (condition_one and
    condition_two):
    print(“Implement this”)

一种方法是使用额外的缩进!

# 使用额外的缩进
if (condition_one and
        condition_two):
    print(“Implement this”)

另外一种方法是在if语句条件和代码块之间添加注释,以区分这二者:

# 添加注释。
if (condition_one and
    condition_two):
    # 此条件有效
    print(“Implement this”)
  • 括号的闭合

假设你有一个很长的字典。你将全部的键值对放在单独的行中,可是你将右括号放在哪里?是在最后一行吗?仍是跟在最后一个键值对?若是放在最后一行,右括号位置的缩进是多少?

也有几种方法能够解决这个问题。

一种方法是将右括号与前一行的第一个非空格字符对齐。

# 
learning_path = {
    ‘Step 1’ : ’Learn programming’,
    ‘Step 2’ : ‘Learn machine learning’,
    ‘Step 3’ : ‘Crack on the hackathons’
    }

第二种方法是把它做为新行的第一个字符。

learning_path = {
    ‘Step 1’ : ’Learn programming’,
    ‘Step 2’ : ‘Learn machine learning’,
    ‘Step 3’ : ‘Crack on the hackathons’
}
  • 在二元运算符前换行

若是你试图在一行中放入太多的运算符和操做数,这确定会很麻烦。相反,为了更好的可读性,把它分红几行。

如今很明显的问题是——在操做符以前仍是以后中断?惯例是在操做符以前断行。这有助于识别操做符和它所做用的操做数。

# 在操做符以前断行
gdp = (consumption
      + government_spending
      + investment
      + net_exports
      )

使用空行

将代码行聚在一块儿只会使读者更难理解你的代码。使代码看起来更整洁、更美观的一个好方法是在代码中引入相应数量的空行。

  • 顶层函数和类应该用两个空行隔开
#分离类和顶层函数
class SampleClass():
    pass


def sample_function():
    print("Top level function")
  • 类中的方法应该用一个空格行分隔
# 在类中分离方法
class MyClass():
    def method_one(self):
        print("First method")

    def method_two(self):
        print("Second method")
  • 尽可能不要在具备相关逻辑和函数的代码段之间包含空行
def remove_stopwords(text): 
    stop_words = stopwords.words("english")
    tokens = word_tokenize(text) 
    clean_text = [word for word in tokens if word not in stop_words] 
      
    return clean_text
  • 能够在函数中少用空行来分隔逻辑部分。这使得代码更容易理解
def remove_stopwords(text): 
    stop_words = stopwords.words("english")
    tokens = word_tokenize(text) 
    clean_text = [word for word in tokens if word not in stop_words] 

    clean_text = ' '.join(clean_text)
    clean_text = clean_text.lower()

    return clean_text

行最大长度

  • 一行不超过79个字符

当你用Python编写代码时,不能在一行中压缩超过79个字符。这是限制,应该是保持声明简短的指导原则。

  • 你能够将语句拆分为多行,并将它们转换为较短的代码行
# 分红多行
num_list = [y for y in range(100) 
            if y % 2 == 0 
            if y % 5 == 0]
print(num_list)

导入包

许多数据科学家之因此喜欢使用Python,部分缘由是由于有太多的库使得处理数据更加容易。所以,咱们假设你最终将导入一堆库和模块来完成数据科学中的任何任务。

  • 应该始终位于Python脚本的顶部
  • 应在单独的行上导入单独的库
import numpy as np
import pandas as pd

df = pd.read_csv(r'/sample.csv')
  • 导入应按如下顺序分组:

    • 标准库导入
    • 相关第三方进口
    • 本地应用程序/库特定导入
  • 在每组导入后包括一个空行
import numpy as np
import pandas as pd
import matplotlib
from glob import glob
import spaCy 
import mypackage
  • 能够在一行中从同一模块导入多个类
from math import ceil, floor

熟悉正确的Python注释

理解一段未注释的代码多是一项费力的工做。即便是代码的原始编写者,也很难记住一段时间后代码行中到底发生了什么。

所以,最好及时对代码进行注释,这样读者就能够正确地理解你试图用这段代码实现什么。

通常提示

  • 注释老是以大写字母开头
  • 注释应该是完整的句子
  • 更新代码时更新注释
  • 避免写显而易见之事的注释

注释的风格

  • 描述它们后面的代码段
  • 与代码段有相同的缩进
  • 从一个空格开始
# 从用户输入字符串中删除非字母数字字符。
import re

raw_text = input(‘Enter string:‘)
text = re.sub(r'\W+', '  ', raw_text)

内联注释

  • 这些注释与代码语句位于同一行
  • 应与代码语句至少分隔两个空格
  • 以一般的#开头,而后是空格
  • 不要用它们来陈述显而易见的事情
  • 尽可能少用它们,由于它们会分散注意力
info_dict = {}  # 字典,用于存储提取的信息

文档字符串

  • 用于描述公共模块、类、函数和方法
  • 也称为“docstrings”
  • 它们之因此能在其余注释中脱颖而出,是由于它们是用三重引号括起来的
  • 若是docstring以单行结尾,则在同一行中包含结束符“””
  • 若是docstring分为多行,请在新行中加上结束符“””
def square_num(x):
    """返回一个数的平方."""
    return x**2

def power(x, y):
    """多行注释。
       返回x**y.
    """
    return x**y

Python代码中的空格

在编写漂亮的代码时,空格经常被忽略为一个微不足道的方面。可是正确使用空格能够大大提升代码的可读性。它们有助于防止代码语句和表达式过于拥挤。这不可避免地帮助读者轻松地浏览代码。

关键

  • 避免将空格当即放在括号内
# 正确的方法
df[‘clean_text’] = df[‘text’].apply(preprocess)
  • 不要在逗号、分号或冒号前加空格
# 正确
name_split = lambda x: x.split()
  • 字符和左括号之间不要包含空格
# 正确
print(‘This is the right way’)
# 正确
for i in range(5):
    name_dict[i] = input_list[i]
  • 使用多个运算符时,只在优先级最低的运算符周围包含空格
# 正确
ans = x**2 + b*x + c
  • 在分片中,冒号充当二进制运算符

它们应该被视为优先级最低的运算符。每一个冒号周围必须包含相等的空格

# 正确
df_valid = df_train[lower_bound+5 : upper_bound-5]
  • 应避免尾随空格
  • 函数参数默认值不要在=号周围有空格
def exp(base, power=2):
    return base**power
  • 请始终在如下二进制运算符的两边用单个空格括起来:

    • 赋值运算符(=,+=,-=,等)
    • 比较(=,<,>!=,<>,<=,>=,输入,不在,是,不是)
    • 布尔值(and,or,not)
# 正确
brooklyn = [‘Amy’, ‘Terry’, ‘Gina’, 'Jake']
count = 0
for name in brooklyn:
    if name == ‘Jake’:
        print(‘Cool’)
        count += 1

Python的通常编程建议

一般,有不少方法来编写一段代码。当它们完成相同的任务时,最好使用推荐的编写方法并保持一致性。我在这一节已经介绍了其中的一些。

  • 与“None”之类的进行比较时,请始终使用“is”或“is not”。不要使用相等运算符
# 错误
if name != None:
    print("Not null")
# 正确
if name is not None:
    print("Not null")
  • 不要使用比较运算符将布尔值与TRUE或FALSE进行比较。虽然使用比较运算符可能很直观,但没有必要使用它。只需编写布尔表达式
# 正确
if valid:
    print("Correct")
# 错误
if valid == True:
    print("Wrong")
  • 与其将lambda函数绑定到标识符,不如使用泛型函数。由于将lambda函数分配给标识符违背了它的目的。回溯也会更容易
# 选择这个
def func(x):
    return None

# 而不是这个
func = lambda x: x**2
  • 捕获异常时,请命名要捕获的异常。不要只使用一个光秃秃的例外。这将确保当你试图中断执行时,异常块不会经过键盘中断异常来掩盖其余异常
try:
    x = 1/0
except ZeroDivisionError:
    print('Cannot divide by zero')
  • 与你的返回语句保持一致。也就是说,一个函数中的全部返回语句都应该返回一个表达式,或者它们都不该该返回表达式。另外,若是return语句不返回任何值,则返回None而不是什么都不返回
# 错误
def sample(x):
    if x > 0:
        return x+1
    elif x == 0:
        return
    else:
        return x-1

# 正确
def sample(x):
    if x > 0:
        return x+1
    elif x == 0:
        return None
    else:
        return x-1

若是要检查字符串中的前缀或后缀,请使用“.startswith()”和“.endswith()",而不是字符串切片。它们更干净,更不容易出错

# 正确
if name.endswith('and'):
    print('Great!')

自动格式化Python代码

当你编写小的程序时,格式化不会成为一个问题。可是想象一下,对于一个运行成千行的复杂程序,必须遵循正确的格式规则!这绝对是一项艰巨的任务。并且,大多数时候,你甚至不记得全部的格式规则。

咱们如何解决这个问题呢?好吧,咱们能够用一些自动格式化程序来完成这项工做!

自动格式化程序是一个程序,它能够识别格式错误并将其修复到位。Black就是这样一种自动格式化程序,它能够自动将Python代码格式化为符合PEP8编码风格的代码,从而减轻你的负担。

BLACK:https://pypi.org/project/black/

经过在终端中键入如下命令,可使用pip轻松安装它:

pip install black

可是让咱们看看black在现实世界中有多大的帮助。让咱们用它来格式化如下类型错误的程序:

如今,咱们要作的就是,前往终端并键入如下命令:

black style_script.py

完成后,black可能已经完成了更改,你将收到如下消息:

一旦再次尝试打开程序,这些更改将反映在程序中:

正如你所看到的,它已经正确地格式化了代码,在你不当心违反格式化规则的状况下它会有帮助。

Black还能够与Atom、Sublime Text、visualstudio代码,甚至Jupyter Notebook集成在一块儿!这无疑是一个你永远不会错过的插件。

除了black,还有其余的自动格式化程序,如autoep8和yapf,你也能够尝试一下!

结尾

咱们已经在Python风格教程中讨论了不少关键点。若是你在代码中始终遵循这些原则,那么你将最终获得一个更干净和可读的代码。

另外,当你做为一个团队在一个项目中工做时,遵循一个共同的标准是有益的。它使其余合做者更容易理解。开始在Python代码中加入这些风格技巧吧!

原文连接:https://www.analyticsvidhya.c...

欢迎关注磐创AI博客站:
http://panchuang.net/

sklearn机器学习中文官方文档:
http://sklearn123.com/

欢迎关注磐创博客资源汇总站:
http://docs.panchuang.net/