资讯专栏INFORMATION COLUMN

Python编程规范笔记(上)

Kross / 1420人阅读

摘要:编程规范笔记上写在前面从语言开始,自己陆续学习了,但是自从研究生做毕设接触以来,就爱不释手,再也没有动力尝试其他语言。一与的一大优势就是具备优秀的可读性,而这基于一套较为完整的公认编程规范。如原本希望的结果是,结果却完全一样。

Python编程规范笔记(上) 写在前面:

从C语言开始,自己陆续学习了C++/Java,但是自从研究生做毕设接触Python以来,就爱不释手,再也没有动力尝试其他语言。然而惭愧的是,由于一直从事科研工作,因为很少关注代码规范性与代码效率,导致自己之前论文所做实验代码可读性极差。故而忙里抽闲得一半日,粗揽《Python编程之美》,收货颇丰,故而重做于屏幕前,权当整理记录。由于全书于己涉及知识点不少,故而仅挑选当前急用者梳理之。

一、PEP_8与PEP_20

Python的一大优势就是具备优秀的可读性,而这基于一套较为完整的公认编程规范。这里建议所有初学或使用Python的同学,可以先从PEP_8入手,其中包括了命名、空格、换行以及函数参数等多个最常用最基本的编程规范。

以自己为例,通常命名变量都采取大小写组合的形式,如一个表示用户特征的变量,通常会命名为Users_Feats_lst,而阅读了PEP_8之后才发觉这样写十分不美观,导致读起来十分混乱,推荐的命名规范是:

常量可以采用全大写;

类名可以采用HelloWorld的单词首字母大写形式;

其余函数与变量名,全部推荐采用小写形式;

上面是自己初读完PEP_8立刻就用上的一点小规范,感觉很实用。因此建议大家在开始Python前抽出十分钟先读读PEP_8/20,后者是对于前者的一个扩充升级,不过我建议初学的同学先从8开始就可以了,逐步学习即可。

PEP8 -- Python代码样式指南(中文版)


二、一般性建议归纳

这部分我们就开始梳理感觉最实用的规范了。

2.1 明确胜于隐晦

Python中提供了同一功能的多种编码实现方式,那么越明确越简练的方式就越推荐。判断代码写得是否优雅的一个经验法则是:其他开发者是否可以只阅读函数的首行与末行就理解函数的作用。

2.2 留白胜于紧凑

Python一般要求一行仅写一个语义句,避免多步处理写在同一行;当然,如果一个长参数函数可以在函数部分断行,如使用反斜杠**或者小括号。

2.3 尽量仅在一处返回函数结果

当遇到多情况的if-else判断时,往往可以在每个判断后返回结果,然而这与具有多重出口的迷宫一样,会降低可读性,故而一般要求函数写成仅有一个返回return的形式。


三、约定 3.1 检查相等性的替代方法

对于和逻辑变量以及0比较的情况,相等性检查全部建议替换为直接使用if语句,如下述情况就推荐2)的形式。

1)if flag_0 == True:
    pass
2)if flag_0:
    pass
3.2 操作列表(列表解析与filter/map函数)

一般而言循环操作列表时我们都喜欢使用以下方法,如从下述列表中筛选出大于等于4的元素:

a = range(10)
b = []
for ele in a:
    if a > 4:
        b.append(ele)
    else:
        continue
print b

然而,现在我们要推荐一种更为简洁优美的方法:列表解析

a = range(10)
b = [i + 2 for i in a if i > 4]
print b
-->[7, 8, 9, 10, 11]

即,我们只要遵循格式[ele operator | ele from where | ele condation]即可,进一步地,上述代码结果说明不仅可以设置筛选特定条件的元素,进一步还可以对每个元素进行运算。

当然,如果上面的公式你感觉别扭不容易读,那么也可以使用同样功能的函数,只是筛选对应filter(),运算对应map(),其中filter函数返回筛选条件为True的元素组成的新列表,而map函数返回函数操作结果组成的新列表。

c = filter(lambda x : x > 4, a)
print c
-->[5, 6, 7, 8, 9]
d = map(lambda x : x * x, a)
print d
-->0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
3.3 解包

解包操作主要用于已知列表或者元祖长度的情况下分配元素,其一般通用公式为:

taget_1, taget_2,...,target_N=长度N的列表或者元祖

需要注意的是,仅在Python 3.0以上版本中,才支持可变目标参数的解包(Unpack)

3.4 创建一个包含N个相同对象的列表

你可能会想这还不简单?但是其实很容易犯错,我们先给出总结的规律:

若非可变对象*N,可以得到正确的N个相同对象的列表

对于空对象[]*N,结果依旧是空对象[]

对于可变对象[[]]*N,其结果默认是N个指向同一个列表的对象列表

# case 1
four_nones = [None]
print four_nones * 4
-->[None, None, None, None]
# case 2
four_nones = []
print four_nones * 4
-->[]
# case 3
four_nones = [[]] * 4
print four_nones 
-->[[], [], [], []]
four_nones[0].append(1) # still be list, so save the copy attr
print four_nones
-->[[1], [1], [1], [1]]
four_nones[0] = 2 # changed to be integer not list
print four_nones
-->[2, [1], [1], [1]]
# suggest format: 列表解析
four_nones = [[] for i in range(4)]
four_nones[0].append(100)
print four_nones
-->[[100], [], [], []]

四、常见陷阱

所谓陷阱,自然是容易犯错的部分,这里简单梳理两例。

4.1 可变的默认参数

有些时候我们希望定义一个可供调用的函数,其中包含一个可变参数以适应不同调用场景。如:

# wrong case:
def append_to(ele, to=[]):
    to.append(ele)
    return to
my_list_1 = append_to(10)
print my_list_1
-->[10]
my_list_2 = append_to(20)
print my_list_2
-->[10, 20]

细心的同学可能发现了,我们本希望两次函数调用分别得到[10]与[20],结果第二次执行时却保留了第一次执行的结果,也就是说,虽然我们使用了可变参数作为默认参数,导致其并未在后续调用时刷新。Python在函数定义而非调用时自动计算其默认参数。

一个解决的简单方法是,直接设置一个默认值表示没有提供默认参数,而是每次重新初始化对象:

def append_to(ele, to=None):
    if to is None:
        to=[]
    to.append(ele)
    return to
my_list_1 = append_to(10)
print my_list_1
-->[10]
my_list_2 = append_to(20)
print my_list_2
-->[20]
4.2 延迟绑定的闭包

有些时候,我们希望可以采用循环的方式创建多个唯一性函数,而这时候其中的循环变量带来的延迟绑定可能导致错误。如:

# wrong case:
def create_multipliers():
    return [lambda x : x * i for i in range(5)]
for multiplier in create_multipliers():
    print multiplier(2)
-->8
-->8
-->8
-->8
-->8

原本希望的结果是[0,2,4,6,8],结果却完全一样。其原因在于for循环依次访问函数对象列表时,肯定函数对象生成函数已经完成,返回的函数对象中i值全部为4,因此导致结果一致。此时只需要多带带绑定一个默认参数i_0,避免受到i值影响即可:

def create_multipliers():
    return [lambda x, i_0 = i : x * i_0 for i in range(5)]
for multiplier in create_multipliers():
    print multiplier(2)
-->0
-->2
-->4
-->6
-->8

五、小结

今天所梳理的部分集中在两个方面:

列表解析带来的列表循环操作的优雅表达法以及创建N个相等对象列表时可能出现的浅复制问题,列表解析属于深复制;

函数调用过程中默认参数在定义时初始化而非调用时初始化,且循环创建唯一性函数时容易受到闭包绑定延迟带来的影响导致程序错误;

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/44017.html

相关文章

  • AI开发书籍分享

    摘要:编程书籍的整理和收集最近一直在学习深度学习和机器学习的东西,发现深入地去学习就需要不断的去提高自己算法和高数的能力然后也找了很多的书和文章,随着不断的学习,也整理了下自己的学习笔记准备分享出来给大家后续的文章和总结会继续分享,先分享一部分的 编程书籍的整理和收集 最近一直在学习deep learning深度学习和机器学习的东西,发现深入地去学习就需要不断的去提高自己算法和高数的能力然后...

    huayeluoliuhen 评论0 收藏0
  • JS学习笔记 - 模块化

    摘要:在开发大型的项目中,可能会使用到管理的模块化工具。说道,学习过的同学会比较熟悉,是服务器模块的规范,采用了这个规范。可能是未来模块化解决方案的首选。 本文章记录本人在学习 JavaScript 中理解到的一些东西,加深记忆和并且整理记录下来,方便之后的复习。 在开发大型的web项目中,可能会使用到管理js的模块化工具。但是在前端轮子漫天飞的时代。那一款js模块化工具真正适合我...

    CntChen 评论0 收藏0

发表评论

0条评论

Kross

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<