鱼C论坛

 找回密码
 立即注册
查看: 6419|回复: 24

[技术交流] <编程技巧> 代码规范

[复制链接]
发表于 2015-3-18 23:36:12 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能^_^

您需要 登录 才可以下载或查看,没有账号?立即注册

x
本帖最后由 戴宇轩 于 2015-3-21 11:31 编辑

    本文主要记录Python中的一些常用技巧,所描述的是告诉你怎么写才是更好
    如果你并不熟悉Python语法,希望你能在下面代码片段中看到Python的简单、优雅
    如果你对 Python 有兴趣我相信下面的技巧并不会让你失望

Python 禅道
这是Python的指导原则,但有不同诠释。
美丽优于丑陋。 
明确优于含蓄。 
简单比复杂好。 
平版优于嵌套。 
稀疏比密集更好。 
特殊情况不能特殊到打破规则。 
错误不应该默默传递。 
......



代码风格: 提高可读性
Programs must be written for people to read, and only incidentally for machines to execute.
     —Abelson & Sussman, Structure and Interpretation of Computer Programs


PEP-8 Python 代码风格指南: http://www.python.org/dev/peps/pep-0008/

空格(行)使用---1:
1. 使用 4 个空格缩进。
2. 不要使用制表符。
3. 不要将制表符和空格混合使用。
4. 每个函数之间应该有一个空行。
5. 每一个 Class 之间应该有两个空行。


空格(行)使用---2:
1.在使用 字典(dict), 列表(list), 元组(tuple), 参数(argument)列表时, 应在 "," 前添加一个空格, 并且使用字典(dict)时,在 ":" 号后添加空格
在括号之前或参数之前不添加空格。
文档注释的前后不要有空格。

示范:
def make_squares(key, value=0):  
    """Return a dictionary and a list..."""  
    d = {key: value}  
    l = [key, value]  
    return d, l


命名
joined_lower 可以是 函数名, 方法名, 属性名
joined_lower or ALL_CAPS 是常量
StudlyCaps 类名
camelCase 只有在预先制定好的命名规范使用
属性: interface, _internal, __private
但尽量避免__private形式。下面两个链接解释了 为什么python中没有 private声明?
      http://stackoverflow.com/questions/70528/why-are-pythons-private-methods-not-actually-private
      http://stackoverflow.com/questions/1641219/does-python-have-private-variables-in-classes


较长代码行
1. 保持一行代码在 80 个字符长度。
2. 在括号内使用隐含的行延续,例如:
def __init__(self, first, second, third,  
            fourth, fifth, sixth):  
   output = (first + second + third  
             + fourth + fifth + sixth)


或者在需要换行的位置使用 \ 来延续行,例如:
VeryLong.left_hand_side \  
    = even_longer.right_hand_side()


另外,使用反斜杠是有风险的,如果你添加一个空格在反斜杠后面,它就出错了。此外,它使代码难看。


较长字符串
将相邻的字符串进行连接的做法:
>>> print 'o' 'n' "e"  
one


虽然字符之间的空格不是必需的,但是这样有助于可读性。
>>> print 't' r'\/\/' """o"""  
t\/\/o
  

用一个 “r“ 开头的字符串是一个“raw“的字符串(类似java中的转义符)。上面的反斜杠就会当成普通字符串处理。他们对正则表达式和Windows文件系统路径非常有用。
注意: 使用字符串变量名无法通过以上方式进行连接。
>>> a = 'three'  
>>> b = 'four'  
>>> a b  
  File "<stdin>", line 1  
    a b  
      ^  
SyntaxError: invalid syntax


这是因为自动连接是由Python解析器/编译器来处理的,因为其无法在编译时对变量值进行"翻译",所以就这种必须在运行时使用“+“运算符来连接变量。


复合语句
Good:
if foo == 'blah':  
    do_something()  
do_one()  
do_two()  
do_three()


Bad:
if foo == 'blah': do_something()  
do_one(); do_two(); do_three()



文档注释(Docstrings) & 注释
文档注释 = 用于解释如何使用代码
      文档注释公约:http://www.python.org/dev/peps/pep-0257/
注释 = 为什么 (理由) & 代码如何工作的如:
# !!! BUG: ...  
# !!! FIX: This is a hack  
# ??? Why is this here?

注释对于任何语言开发者来说已经最基本的东西了,这里就不详细说了.


交换变量
在其它语言的交换变量的做法一般是:
temp = a 
a = b  
b = temp


Python的做法:
b, a = a, b


也许你见到过这样的情况,但是你知道它是如何工作的吗?
首先,逗号是元组构造语法。
等号的右边是定义一个元组 (tuple packing).
其左边为一个目标元组 (tuple unpacking)).
右边的元组根据名称被 unpacked 到左边的无组。
更多关于 unpacked例子:
>>> info =['David', 'Pythonista', '+1250']  
>>> name, title, phone = info  
>>> name  
'Davids'  
>>> title  
'Pythonista'  
>>> phone  
'+1250'


在结构化的数据上使用循环:
info 是在上面定义的一个 list . 所以下面的 people 有两个项,  两个项都是分别都拥有三个项的 list.
>>> people = [info, ['Guido', 'BDFL', 'unlisted']]  
>>> for (name, title, phone) in people:  
...     print(name, phone)
...  
David +1250  
Guido unlisted


以上循环中,people中的两个项(list item),都已经被 unpacked 到 (name, title, phone) 无组中。
可以任意嵌套(只要左右两边的结构一定要能够匹配得上):
>>> david, (gname, gtitle, gphone) = people  
>>> gname  
'Guido'  
>>> gtitle  
'BDFL'  
>>> gphone  
'unlisted'  
>>> david  
['David', 'Pythonista', '+1250']



更多关于 Tuples
我们看到的是元组通过逗号构造,而不是括号。例如:
>>> 1,  
(1,)


Python的解释器会为你显示括号,所以建议你使用括号:
>>> (1,)  
(1,)


千万不要忘记逗号!
>>> (1)  
1


在只有一个元素的元组,尾随逗号是必须的,在2 + 元素的元组,尾随逗号是可选的。 如果创建一个 0或空元组,一对括号是快捷的语法:
>>> ()  
()  
>>> tuple()  
()


一个常见的&#8203;&#8203;错误当你并不想要一个无组,却无意的添加了一个逗号,很容易造成你在代码中的错误,如:
>>> value = 1,  
>>> value # is a tuple, not a int  
(1,)


所以,当你发现一个元组时,赶紧去找一下那个,号吧。


关于 "_"
是一个非常有用的功能,但是却很少有人知道。
当你在交互式模式下(如 IDEL)计算一个表达式或调用一个函数后,其结果必然是一个临时名称,_(下划线):
>>> 1 + 1  
2  
>>> _  
2


在 _ 中存储最后输出的值。
当输出的结果是 None 或没有任何输出时,而 _ 的值并不会改变,仍然保存上一次的值。这就是方便所在。
当然,这只能交互式的模式中使用,在模块中不能支持。
这在交互式模式中是非常有用的,当你在过程中没有保存计算结果 或 你想看最后一步的执行的输出结果:
>>> import math  
>>> math.pi / 3  
1.0471975511965976  
>>> angle = _  
>>> math.cos(angle)  
0.50000000000000011  
>>> _  
0.50000000000000011



创建String: 从列表中创建
开始定义一个 string  列表:
colors = ['red', 'blue', 'green', 'yellow']

当我们需要将上面的列表连接成一个字符串。尤其当 list 是一个很大的列表时....
不要这样做:
result = ''  
for s in colors:  
    result += s

这种方式效率非常低下的,它有可怕的内存使用问题,至于为什么,如果你是 javaer 的话,其中的 string 连接,我想你并不陌生。
相反,你应该这样做:
result = ''.join(colors)


当你只有几十或几百个string项连接时,它们效率上并不会太大的差别。但你要在养成写高效代码的习惯,因为当字符串数千时,join 比起 for 连接性能会能有所提升。

如果你需要使用一个函数来生成一个字符串列表,同样可以使用:
result = ''.join(fn(i) for i in items)



尽可能的使用
Good:
for key in d:  
    print key


使用 in 一般情况下是非常快的。
这种方式也适用于其它的容器对象(如 list,tuple 和 set)。


字典中的 get 函数
我们经常需要在字典中初始化数据:
以下是不好的实现方法:
<navs = {}  
for (portfolio, equity, position) in data:  
    if portfolio not in navs:  
        navs[portfolio] = 0  
    navs[portfolio] += position * prices[equity]<


使用dict.get(key, default) 删除 if 判断代码:
navs = {}  
for (portfolio, equity, position) in data:  
    navs[portfolio] = (navs.get(portfolio, 0)  
                       + position * prices[equity])

这种方式更为直接。


字典中的 setdefault 函数---1
当我们要初始化一个可变字典的值。每个字典的值将是一个列表。下面是不好的做法:
初始化可变字典的值:
equities = {}  
for (portfolio, equity) in data:  
    if portfolio in equities:  
        equities[portfolio].append(equity)  
    else:  
        equities[portfolio] = [equity]


通过 dict.setdefault(key, default) 使这段代码工作的更好:
equities = {}  
for (portfolio, equity) in data:  
    equities.setdefault(portfolio, []).append(  
                                         equity)


dict.setdefault() 等同于“ get, or set & get“ 或"如果没有,就设置";  如果你的字典Key是复杂的计算或long类型,使用 setdefault 是特别有效的。


字典中的 setdefault 函数---2
在我们看到的setdefault字典方法也可以作为一个独立的语句使用:
avs = {}  
for (portfolio, equity, position) in data:  
    navs.setdefault(portfolio, 0)  
    navs[portfolio] += position * prices[equity]


我们在这里忽略了字典的setdefault方法返回的默认值。我们正利用的setdefault中的作用,仅仅只是在dict中没有 key 的值的时候才会设置。


创建 & 分割字典
如果你有两份 list 对象,希望通过这两个对象构建一个 dict 对象。
given = ['John', 'Eric', 'Terry', 'Michael']  
family = ['Cleese', 'Idle', 'Gilliam', 'Palin']  
pythons = dict(zip(given, family))  
>>> pprint.pprint(pythons)  
{'John': 'Cleese',  
 'Michael': 'Palin',  
 'Eric': 'Idle',  
 'Terry': 'Gilliam'}


同样,如果希望获取两份列表,也是非常简单:
>>> pythons.keys()  
['John', 'Michael', 'Eric', 'Terry']  
>>> pythons.values()  
['Cleese', 'Palin', 'Idle', 'Gilliam']


需要注意的是,上面 list 虽然是有序的,但是 dict 中的  keys 和 values 是无序的,这正是因为 dict 本质就是无序存储的。


索引 & 项---1
如果你需要一个列表,这里有一个可爱的方式来节省你的输入:
>>> items = 'zero one two three'.split()  
>>> print(items)
['zero', 'one', 'two', 'three']


如果我们需要遍历这个 list ,而且需要 index 和 items:
i = 0  
for item in items:
    print(i, item)
    i += 1

# 或者
for i in range(len(items)):
    print(i, items[i])


索引 & 项---2: enumerate
通过 enumerate 可以返回 list 中的 (index, item)元组:
>>> print(list(enumerate(items)))
[(0, 'zero'), (1, 'one'), (2, 'two'), (3, 'three')]


于是,遍历list获取index 及 item 就更加简单了:
for (index, item) in enumerate(items):  
    print(index, item)

# 等同于
index = 0
for item in items:
    print index, item
    index += 1

# 或者
for i in range(len(items)):
    print(i, items[i])
不难看出,使用 enumerate 比起下面两种方式,更加简单,更加容易阅读,这正是我们想要的。 
下面是例子是如何通过 enumerate 返回迭代器:[code]>>> enumerate(items)  
<enumerate object at 0x011EA1C0>  
>>> e = enumerate(items)  
>>> e.next()  
(0, 'zero')  
>>> e.next()  
(1, 'one')  
>>> e.next()  
(2, 'two')  
>>> e.next()  
(3, 'three')  
>>> e.next()  
Traceback (most recent call last):  
  File "<stdin>", line 1, in ?  
StopIteration



默认参数值
这是对于一个初学者常犯的错误,甚至于一些高级开发人员也会遇到,因为他们并不了解 Python 中的 names.
def bad_append(new_item, a_list=[]):  
    a_list.append(new_item)  
    return a_list


这里的问题是,a_list是一个空列表,默认值是在函数定义时进行初始化。因此,每次调用该函数,你会得到不相同的默认值。尝试了好几次:
>>> print bad_append('one')  
['one']  
>>> print(bad_append('two'))
['one', 'two']


列表是可变对象,你可以改变它们的内容。正确的方式是先获得一个默认的列表(或dict,或sets)并在运行时创建它。
def good_append(new_item, a_list=None):  
    if a_list is None:  
        a_list = []  
    a_list.append(new_item)  
    return a_list



判断 bool 值
# 这样做
if x:
    pass
# 不要这样做
if x == True:
    pass<

它的优势在于效率和优雅。
判断一个list是否不为空:
# 要这样做    
if items:
    pass

# 不要这样做
if len(items):
    pass

# 千万不要这样做!
if items != []:
    pass

评分

参与人数 1荣誉 +10 鱼币 +10 贡献 +10 收起 理由
~风介~ + 10 + 10 + 10 感谢楼主无私奉献!

查看全部评分

本帖被以下淘专辑推荐:

想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2015-4-11 08:26:26 | 显示全部楼层
谢谢楼主分享!
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2015-4-17 14:08:46 | 显示全部楼层
好东西!继续努力!
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2015-9-24 07:38:33 | 显示全部楼层
还没看完,留着
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2015-9-24 09:21:35 | 显示全部楼层
每天回帖赚鱼币
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2015-9-24 18:00:58 | 显示全部楼层
受教了
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2015-10-1 21:02:20 | 显示全部楼层
學習中 有時會看看google的規範
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2015-11-10 12:10:58 | 显示全部楼层
作为一名优秀的工程师,基层建筑不可少,整体美观很重要。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2015-11-13 14:07:09 | 显示全部楼层
学习,实践
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2015-11-18 18:41:12 | 显示全部楼层
GOOD
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2015-12-29 16:33:05 | 显示全部楼层
好东西,必须支持,支持小甲鱼!!!
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2016-2-16 20:28:10 | 显示全部楼层
学习了、、、
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

头像被屏蔽
发表于 2016-2-19 16:47:08 | 显示全部楼层
提示: 作者被禁止或删除 内容自动屏蔽
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2016-3-22 23:44:41 | 显示全部楼层
  真的不错,好好学习中!
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2016-3-23 09:55:55 | 显示全部楼层
好分享
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2016-4-16 13:56:43 | 显示全部楼层
能不能gi答案
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2016-4-25 23:54:45 | 显示全部楼层
必须赞一个!
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2016-11-17 21:16:21 | 显示全部楼层
很多实用的技巧,如果有关于函数变量类成员命名规范的就更好了
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2018-5-8 10:55:34 | 显示全部楼层
很实用,谢谢
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2018-5-20 14:53:30 | 显示全部楼层
好东西,新手非常有用
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2024-11-22 13:34

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表