Python风格的要素
Python风格的要素,本文超出PEP8来覆盖我认为良好的Python风格的核心。这是固执己见,但是不要太固执己见。它不仅仅是语法问题和模块布局,也在范式,组织和架构领域。我希望它可以是Python代码“断词和空格”的一个浓缩。
遵循大部分PEP8指南
…但是,命名和行长度是灵活的。
PEP8覆盖大量常见的东西如空格,方法/类/函数之间的换行符,导入,使用弃用的功能的警告。在那里几乎所有的东西都是好的。
flake8是执行这些规则的最佳工具,同时也可以帮你捕获愚蠢的Python语法错误。
PEP8是一套指南,而不是严格的规则,或信仰,紧随其后。请务必阅读PEP8标题为:“令人讨厌的小人物身上愚蠢的一致性”的部分。获取更多信息看看RaymondHettinger的精彩演讲“超越PEP8”。
唯一的规则集,似乎导致过多的争议的是围绕行长度和命名。这些很容易调整。
行长度的灵活性
如果flake8中严格的79个字符的行长度规则困扰你,不妨忽略或调整该规则。它可能仍然是一个很好的经验法则——像“规则”,英语句子应该有50个或更少的单词,段落应该少于10个句子。这是flake8配置的链接,查看配置选项max-line-length。还要注意一行增加#noqa注释会使flake8检查被忽略,请谨慎使用这些。
90%+的行应该是79个字符或者更少,原因很简单,“平直优于嵌套”。如果一个函数的所有行都比这长,别的地方还有毛病,你应该看看你的代码而不是flake8的设置。
命名一致性
在命名上,遵循一些简单的规则可以防止很多杯具。
首选的命名规则
这些大都源于Pocoo团队。
类名:驼峰命名法,和大写首字母缩略词:HTTPWriter,而不是HttpWriter。
变量名:带下划线的小写字母。
方法和函数名:带下划线的小写字母。
模块:带下划线的小写字母.py。(但是,首选不带下划线的名字!)
常量:带下划线的大写字母。
预编译正则表达式:名字_re。
通常应该遵循这些规则,除非你正在借鉴其它工具的命名规则,如数据库模式或消息格式。
对于像类但不是类的也可以选择使用驼峰命名法—驼峰命名法的最大好处是提醒注意一些东西作为“全局名词”,而不是一个局部标签或动词。请注意Python中名字True,False,和None,虽然它们不是类却使用的是驼峰命名法。
避免使用名字装饰器
…如_前缀或后缀_。函数和方法可以使用_前缀表示法表示“私有”,但是应该谨慎使用并且仅用于预计被广泛使用的API,并且用_private指示器协助信息隐藏。
PEP8建议使用后置下划线来避免混淆内置,例如
sum_=sum(some_long_list)
print(sum_)
必要时这是可行的,但是最好选择一个不同的名字。
类/实例/方法应该很少使用两个前导下划线,它们有特定的行为—很少需要。永远不要用双下划线装饰器创建名字除非要实现Python的标准协议,如__len__;
这是一个专为为Python内部协议预留的命名空间,不应该指派自己的东西。
避免单字符名字
有些单字符的标签名称是常见并且可以接收的。
lambda中,使用x作为单参数的函数是可以的。例如:
encode=lambdax:x.encode("utf-8","ignore")
元组解包,使用_作为一次性标签也是可以的。例如:
_,url,urlref=data
这基本意味着,“忽略第一个元素”。
与lambda相似,在list/dict/set推导式,生成器表达式,或者很短的循环(1-2行),可能使用单字符迭代标签。典型的是x,例如:
sum(xforxinitemsifx>0)
求序列items中所有正整数的和。
用i作为“索引”的简写也很常见,并且通常和内置的enumerate一起。例如:
fori,iteminenumerate(items):
print("%4s:%s"%(i,item))
除此以外,你应该很少,也许绝不,使用单字符标签/参数/函数名。因为它使查找东西不可能。
使用self和类似约定
应该:
函数的第一个参数总叫self
@classmethod的第一个参数总叫cls
变形参数列表使用*args和**kwargs
挑剔,不值得
不遵循这些规则没有任何收获,因此你应该遵循它们。
总是继承object并且使用新型类
#风格不良
classJSONWriter:
pass
#风格良好
classJSONWriter(object):
pass
Python2中,遵循这条规则是很重要的。Python3中,所有类都隐式继承object,这条规则也就没有必要了。
不要在类中重复实例标签
#风格不良
classJSONWriter(object):
handler=None
def__init__(self,handler):
self.handler=handler
#风格良好
classJSONWriter(object):
def__init__(self,handler):
self.handler=handler
喜欢list/dict/set推导式胜过map/filter
#风格不良
map(truncate,filter(lambdax:len(x)>30,items))
#风格良好
[truncate(x)forxinitemsiflen(x)>30]
尽管大部分简单的情况下你应该喜欢推导式,有些场合map()或者filter()可读性更高,请你自己判断用什么。
使用括弧(...)来续行
#风格不良
fromitertoolsimportgroupby,chain,\
izip,islice
#风格良好
fromitertoolsimport(groupby,chain,
izip,islice)
连贯的API使用括弧(...)
#风格不良
response=Search(using=client)\
.filter("term",cat="search")\
.query("match",title="python")
#风格良好
response=(Search(using=client)
.filter("term",cat="search")
.query("match",title="python"))
函数调用时使用隐式续行
#风格不良--不必要的反斜杠
returnset((key.lower(),val.lower())\
forkey,valinmapping.iteritems())
#风格良好
returnset((key.lower(),val.lower())
forkey,valinmapping.iteritems())
使用isinstance(obj,cls),而不是type(obj)==cls
这是因为isinstance覆盖更多情况,包括子类和基础的。isinstance也很少使用,因为经常用动态类型。
文件和锁使用with
with语句巧妙的处理文件关闭和锁释放,即使引起异常时。因此:
#风格不良
somefile=open("somefile.txt","w")
somefile.write("sometext")
return
#风格良好
withopen("somefile.txt","w")assomefile:
somefile.write("sometext")
return
与None相比较时使用is
None值是单值,当检查None时,很少想要在左边参数调用__eq__。因此:
#风格不良
ifitem==None:
continue
#风格良好
ifitemisNone:
continue
好的形式不仅更快,也更正确。使用==不是更简洁的,请记住这条规则!
避免sys.path技巧
很容易使用sys.path.insert(0,"../")和类似的控制Python导入方式,但是你应该避开这些像避开瘟疫一样。
Python中模块路径解析有一点复杂,但是很容易理解。可以通过PYTHONPATH或setup.pydevelop的技巧来调整Python加载模块的方式。也可以使用-m来很好的运行Python,例如python-mmypkg.mymodule而不是pythonmypkg/mymodule.py。运行Python代码正常工作,不应该依赖当前工作目录。
DavidBeazley的PDF“模块和包:生死关头”值得再次浏览。
很少创建自定义异常类型
...并且当你必须创建自定义异常类型时,不要创建太多。
#风格不良
classArgumentError(Exception):
pass
...
raiseArgumentError(url)
#风格良好
raiseValueError("badvalueforurl:%s"%url)
请注意Python包括一组丰富的内置异常类。适当地利用这些,只需通过实例化字符串消息描述遇到的特定错误来“定制”它们。用户代码中最常见引发ValueError(错误参数),LookupError(错误码),或者AssertionError(通过assert语句)
一个好的经验法则是,通过分析调用者每次调用你的函数时是否都捕获异常来判断是否创建自定义异常类型。如果是,你可能应该自定义。但这比较罕见。tornado.web.HTTPError是异常类型的一个很好的例子。但注意Tornado不走极端:一个异常类就包括了框架或用户代码引起的所有的HTTP错误。
简短的文档字符串是一行适当的句子
#风格不良
defreverse_sort(items):
"""
sortitemsinreverseorder
"""
#风格良好
defreverse_sort(items):
"""Sortitemsinreverseorder."""
保持三重引号"""在同一行,首字母大写,并且包括一个句号。四行变成两行,__doc__属性没有过于复杂的换行。
为文档字符串使用reST
它是由stdlib和大多数开源项目完成。通过Sphinx它支持开箱即用。Python的requests模块使用这些效果非常好。查看requests.api模块。
去掉尾部空格
这也许是终极挑剔,但是如果你不这样做,它会让人发疯。文本编辑器里没有工具自动为你做这件事;这是我用的vim版本的。
编写好的文档字符串
这是在函数文档字符串中使用Sphinx风格reST的一个快速参考:
defget(url,qsargs=None,timeout=5.0):
"""SendanHTTPGETrequest.
:paramurl:URLforthenewrequest.
:typeurl:str
:paramqsargs:Convertedtoquerystringarguments.
:typeqsargs:dict
:paramtimeout:Inseconds.
:rtype:mymodule.Response
"""
returnrequest('get',url,qsargs=qsargs,timeout=timeout)
不为记录文档而记录。考虑这个问题的方法是:
好的名字+显示缺省值>冗长的文档+type_specs
在上述例子中,不必说timeout是一个float,因为默认值是5.0,它显然是一个float。文档中指出语义意义是“秒”是有用的,因此5.0意思是5秒。同时,调用者不知道qsargs是什么,因此给出type注释,调用者也不知道函数返回什么,因此rtype注释是适当的。
最后一点。Guido曾经说过关于Python他最重要的见解是,“代码阅读的次数比编写的次数多。”这个的推论是有文档可以帮助,但文档太多有害。
应该主要地文档化你预期被广泛使用的函数。如果文档化内部模块中的每个函数,由于代码重构时文档也需要重构,你会得到更少的可维护模块。不要“货物崇拜”文档,并且绝对不用工具自动生成它们。
范式与模式
函数与类
应该选择函数而不是类。Python中,函数和模块是代码重用的基本单元,它们是最灵活的形式。对于某些Python功能来说类是“提升路径”,例如实现容器,代理,描述符,类型系统,等等。通常,函数是更好的选择。
有些人可能喜欢分组相关函数到类中,这种代码组织。这是一种错误。应该分组相关函数到模块。
尽管有时类可以作为有用的“微型命名空间”(例如@staticmethod),更多的时候一组方法有助于对象的内部操作,而不是仅仅是一个行为分组。
时间相关的函数用lib.time模块总是比TimeHelper类更好,为了使用TimeHelper一系列的方法在子类被迫派生出来!类扩展其它类,复杂性激增并且降低程序可读性。
生成器和迭代器
生成器和迭代器是Python最强大的特性—你应该掌握迭代器协议,关键字yield,和生成器表达式。
生成器不仅在需要被大量数据调用的任何函数时重要,在编写自定义迭代器来简化代码时他们也产生影响。生成器简化代码重构,使它在多个场景中工作。
“FluentPython”的作者LucianoRamalho有一个30分钟的演讲,“Python方式的迭代器和生成器”,它给出了精彩快速的概述。“PythonEssentialReference”和“PythonCookbook”的作者DavidBeazley有一个引人深思的三小时视频教程题目是“生成器:”,它是一个令人满意的阐述关于生成器用例。由于它在哪里都适用,掌握这个主题是值得的。
声明与命令
选择声明式而非命令式编程。代码表达你做什么,而不是描述怎么做。Python的函数式编程指南关于如何有效使用这种风格包括一些有用的细节和例子。
应该使用轻量级数据结构例如列表,字典,元组,和集合成为你的优势。摆放数据,然后编写代码来转换它,胜于反复调用可变函数/方法来建立数据。
常见的例子是列表推导式重构:
#风格不良
filtered=[]
forxinitems:
ifx.endswith(".py"):
filtered.append(x)
returnfiltered
应该写成:
#风格良好
return[x
forxinitems
ifx.endswith(".py")]
另一个很好的例子是重写if/elif/else为dict解析。
Python培训、Python培训班、Python培训机构,就选光环大数据!
还不够过瘾?想学习更多?点击 http://hadoop.aura.cn/python/ 进行Python学习!
大数据培训、人工智能培训、Python培训、大数据培训机构、大数据培训班、数据分析培训、大数据可视化培训,就选光环大数据!光环大数据,聘请专业的大数据领域知名讲师,确保教学的整体质量与教学水准。讲师团及时掌握时代潮流技术,将前沿技能融入教学中,确保学生所学知识顺应时代所需。通过深入浅出、通俗易懂的教学方式,指导学生更快的掌握技能知识,成就上万个高薪就业学子。 更多问题咨询,欢迎点击------>>>>在线客服!