python | 改善Python程序建议- Part1

Python在学完初级语法之后都会面临一个瓶颈,不知道接下来要学什么,也不知道如何独立完成一个实战项目。除了多加练习之外,还应该增加知识摄入,相信量便会引起质变。
 
python学习的三个阶段:
第一个阶段:掌握Python的语法和一些常用库的使用
可以边学语法边刷Leetcode
第二个阶段:中级,掌握自己特定领域的库,掌握pythonic写法,非常熟悉Python的特性
这个阶段了解python工程的文件布局,总结如何写出pythonic的代码;
有机会可以查看源码,彻底了解python的核心机制。(可参考《Python源码剖析——深度探索动态语言核心技术》)
第三阶段::高级,从整个工程项目着眼,考虑document,distribution,性能优化等
 
这个系列主要是总结一些《改善python程序的91个建议》的学习笔记,希望可以对自己和读者有所帮助。本文是该系列第一部分,第二部分请见 Part2
 
1 格式化输出
官方推荐 str.format()
e.g. print (‘{greet} from {language}.’.format(greet = “hello world”, language = ‘python’))
 
2 模块和包
包和模块的命令采用小写、单数形式,而且短小。
包通常仅作为命名空间,如只包含空的__init__.py文件。
 
3 与C的不同
· 三元操作符 eg: x if C else Y
· switch case
 
4 注释的使用
三对"""
· 要清楚地描述方法的功能,并对参数,返回值以及可能发生的异常进行说明;
· 推荐在文件头包含copyright 声明,模块的描述等,如有必要,可以考虑加入作者的信息及变更记录;
e.g.

"""
    Licensed Materials - Property of CorpA
    (C) Copyright A Corp.1999, 2011 All Rights Reserved
    CopyRight statement and purpose....
    ------------------------------------------------------
    File Name : comments.py
    Description: description what the main function of this file

    Author: LF
    change Activity:
            list the change activity and time and author information
    -----------------------------------------------------------
"""
 
5 代码编写建议
· 适当添加空行使代码更为优雅、合理
· 保持上下文的易理解性,如果一个函数需要调用另一个函数,最好放在一起
· 避免过长代码
· 空格的使用
 
6 函数编写
· 函数设计要尽量短小
· 合理的参数设定 参数数量不应过多 同时要考虑向下兼容
eg:前一个 def readfile(filename) 版本升级添加日志 def readfile(filename,logger) —> 应用缺省参数 def readfile(filename,logger=xxx)
· 一个函数只做一件事情,尽量保证函数语句粒度的一致性
· 使用异常处理返回错误,保证通过单元测试等
 
7 将常量集中到一个文件
· 常量的命名 一般是全大写字母 中间用下划线连接 这只是一直约定俗成的风格。如TOTAL,MAX_OVERFLOW
· 通过自定义的类实现常量功能 —>要求:命名全部大写 和 值一旦绑定不可修改 可以通过异常来解决这个问题
e.g.
class _const:
    class ConstError(TypeError): pass
    class ConstCaseError(ConstError): pass
    
    def __setattr__(self, name, value):
        if self.__dict__.has_key(name):
            raise self.ConstError, "Can't change const. %s" %name
        if not name.isupper():
            raise self.ConstCaseError, 
                'const name "%s" is not all uppercase' %name
        self.__dict__[name] = value

import sys
sys.modules[__name__] = _const()

 8 利用assert 语句来发现问题(断言)

assert expression1 ["," expression2]
其中expression1的值会返回True或者False,当值为False的时候会引发AssertionError,而expression2是可选的,常用来传递具体的异常信息。但使用断言有性能成本,使用时需注意。
 
9 数据交换值的时候不推荐使用中间变量
x,y = y,x
10 利用Lazy evaluation 的特性

 延迟计算/惰性计算
- 避免不必要的计算
eg: if x or y 当x为 true时就直接返回 不用计算y
- 节省空间,使用无限循环的数据结构成为可能
eg:生成器表达式 a= (x for x in range(100))—>不会立即生成数据列表 用的时候才会生成 print(a[9])
 
11 不推荐使用type()来进行类型检查
- 基于内建类型扩展的用户自定义类型 type并不能准确返回结果 比如class A(int)
isinstance(object, classinfo)
#其中,classinfo可以为直接或间接类名、基本类型名称或者由它们组成的元祖
#isinstance(2, float)                    False
#isinstance("a", (str,unicode))      True
12 转成浮点后再做除法

但py3已经做了更新,除法不会截断
from __future__ import division
但浮点的运算结果也不一定准确。如果计算对精度要求较高,可以使用decimal来进行处理或者将浮点数尽量扩大为整数,计算完毕之后再转换回去,同时浮点数的比较同样最好能够指明精度。
 
13 警惕eval()安全漏洞
eval()是将字符串改变为有效的表达式
在实际应用过程中,如果使用对象不是信任源,应该尽量避免使用eval,在需要使用eval的地方可以用安全性更好的ast.literal_eval替代。
 
14 使用enumerate()获取序列迭代
每次仅在需要的时候才会产生一个(index,item)对
enumerate(sequence, start=0)
#sequence可以是list、 set等任何迭代对象
#默认从0开始
#函数返回一个迭代器,可以使用next()方法获取下一个元素
15 区分 is 和 ==
 
16 考虑兼容性,尽可能使用Unicode
一般就是向文件传输时 先编码 再到达客户端时解码 a=”你好”.encode(“utf-8”) –> a.decode(“utf-8”)
encode和decode中参数 window 一般是gbk liunx等其他一般是utf-8
 
17 构建合理的包层次来管理module
通过包(Package)来合理的组织项目的层次来管理模块
包与普通目录不同,在于除了包含常规的python文件(模块)以外,还包含一个__init__.py文件,同时它允许嵌套。
Package/ __init__.py
    Module1.py
    Molude2.py
    Subpackage/ __init__.py
        Module1.py
        Module2.py
包使用的好处:
- 合理组织代码,易于维护和使用。以下是一个可供参考的python项目结构:
ProjectName/
|---README
    |----LICENSE
    |----setup.py
    |-----requirements.txt
    |------sample/
    |   |----__init__.py
    |   |----core.py
    |   |----helpers.py
    |------docs/
    |   |------conf.py
    |   |------index.rst
    |------bin/
    |------package/
    |   |-----__init__.py
    |   |-----subpackage/
    |   |-----......
    |------tests/
    |   |------test_basic.py
    |   |------test_advancde.py

- 能够有效地避免名称空间冲突。

 18 有节制地使用from….import语句

· 一般情况优先使用import a —> print a.xxx
· 有节制地使用from a import xxx —> print xxx
· 尽量避免使用from a import * —>污染命名空间

19 i+=1 不等于 ++i

在python中 ++i 不是自增 +(+1) 即正数取正
同理: –i 不是自减 -(-1) 即负数取反

20 使用with自动关闭资源

基本上只要是需要close的都可以用with eg:
with open(xx_file_name,'rb') as f:
        f.read()
实际上任何实现了上下文协议的对象的都可以称为一个上下文管理器->如 打开/关闭文件,异常处理,断开流的连接,锁分配等

参考:

《改善python程序的91个建议》

https://blog.csdn.net/qq_31603575/article/details/80177153

https://www.cnblogs.com/cotyb/p/5452602.html

https://www.cnblogs.com/cotyb/tag/pythonic/

https://medium.freecodecamp.org/an-a-z-of-useful-python-tricks-b467524ee747

原文地址:https://www.cnblogs.com/geo-will/p/9582693.html