-
确认自己所使用的python版本
-
遵循PEP8风格指南
函数、变量及属性应该用小写字母来拼写,各单词之间以下划线相连,例lowercase_underscore.
类与异常:每个单词均大写的形式来命名,例如CaoutlizedWord.
不要编写单行的if语句、for循环、while循环以及except语句
不要通过检测长度的办法来判断somelist是否为[] ,而应该采用 if not somelist这种形式。 -
了解byte、str与unicode的区别
-
用辅助函数来取代复杂的表达式
-
了解切割序列的办法
-
在单次切片操作内,不要同时指定start、end和stride
-
用列表推导式来取代map和filter
-
不要使用含有两个以上表示的列表推导
-
用生成器表达式来改写数据量较大的列表推导
-
尽量使用enumerate取代range
enumerate将各种迭代器包装为生成器,以便稍后产生输出值。
for i, flavor in enumerate(flavor_list):
print(i,flavor)
还可以值得enumerate开始计数的值enumerate(flavor_list)
- 用zip同时遍历两个迭代器
python3中的zip函数,可以把两个或两个以上的迭代器封装为生成器。
names=['aaaaa','ass','aa']
letters=[len(n) for n in names]
for i name in enumerate(names):
count = letters[i]
if count>max_letter:
longest_name =name
max_letters= count
优化
for name,count in zip(names,letters):
if count > max_letter:
longest_name=name
max_letters= count
第一个问题是,python2的zip并不是迭代器。
第二个问题是,如果输入的迭代器长度不同,那么zip就会出现奇怪的行为。
-
不要在for和while循环后面写else块
-
合理利用try/except/else/finally结构中的每一个代码块
handle = open('/tm/data.txt')
try:
data = handle.read())
finally:
handle.close()
在上面这段代码中,read方法所抛出的异常会
向上传播给调用方。
而finally块重handle.close方法则一定能够执行。
open方法必须放在try块后面,
因为如果打开文件时发生异常,
例如,由于找不到该文件而抛出IOError
那么程序应该跳过finally块。
else块
try/except/else 如果try块没有发生异常,
那么则执行else块。
有了这样的else块,可以尽量缩减try块内
的代码量。
def load_json_key(data,key):
try:
result_dict = json.loads(data)
except ValueError as e:
raise KeyError from e
else:
return result_dict[key]
3.混合使用
undefined = object()
def divide_json(path):
handle = open(path,'r+')
try:
data= handle.read()
op=json.loads(data)
value = [
op['numerator']/
op['denominator']
]
except ZeroDivisonError as e:
return UNDEFINED
else:
op['result'] = value
result = json.dumps(op)
handle.seek(0)
handle.write(result)
return value
finally:
handle.close())
-
尽量用异常来表示特殊情况,而不要返回None
-
了解如何在闭包里使用外围作用域中的变量(不太明白)
-
考虑用生成器来改写直接返回列表的函数
def index_words(text):
result=[]
if text:
result.append(0)
for index,letter in enumerate(text):
if letter == ' ':
result.append(index+1)
return result
def index_words_iter(text):
if text:
yield 0
for index,letter in enumerate(text):
if letter == ' ':
yield index+1
result = list(index_words_iter(test))
- 在参数上面迭代时,要多加小心。
如果函数接受的参数是个对象列表,那么很有可能在这个列表上迭代。
- 用数量可变的位置参数减少视觉杂讯
就是使用*args
- 用关键字参数表表达可选的行为
例如sort(reverse=True)
- 用None和文档字符串来描述具有动态默认值的参数
def log(message,when=datetime.now()):
pass
log()
log()
>>>
两条消息的时间戳是一样的
def log(message,when=None):
when=datetime.datetime.now()
def decode(data,default={}):
pass
def decode(data,default=None):
if default is None:
default={}
-
用只能以关键字形式指定的参数来保证代码清晰
-
尽量用辅助类来维护程序的状态,而不要用字典和元组(不太明白)
-
简单的接口应该接受函数,不是类的实例(也是不太明白)
-
以@classmethod形式的多态去通用地构建对象(人又看迷糊了)
类的多态
- 用super初始化父类
初始化父类的传统方式,是在子类中用子类实例直接调用父类的__init__
方法。
问题:1.如果子类收到了多重继承的影响,那么直接调用超类的__init__
方法,可能会产生无法预知的结果。
-
只在使用Mix-in组件制作工具时使用多重继承(尽量别用,不去深究了)
-
多用public属性,少用private属性
-
继承collections.abc以实现自定义的容器类型
-
用纯属性取代get和set方法
class ColrageResistance(Registor):
def __init__(self,ohms):
super().__init__(ohms)
self._voltage=0
@property
def voltage(self):
return self._voltage
@voltage.setter
def vorlage(self,voltage):
设置voltage属性时,会执行名为voltage的setter方法
-
考虑用@property来代替属性重构(感觉我目前不太用得着)
-
用描述符来改写需要复用的@property方法
-
用
__getattr__ __getattrbute__和__setattr__
实现按需生成的属性。 -
用元类来验证子类
元类最简单的一种用途,就是验证某个类定义是否正确。
-
用元类来注册子类
-
用元类来注解类的属性
-
用subprocess来管理子进程
-
可以用线程来执行阻塞式IO,但不要他来进行平行计算。
-
在线程中使用Lock来防止数据竞争
-
用Queue来协调各线程之间的工作
-
考虑用协程来并发地执行多个函数
协程的工作原理:每当生成器函数执行到yield表达式的时候,消耗生成器的那段代码。就通过send方法给生成器回传一个值。而生成器在收到经由send函数所传进来的那个值之后,会将其视为yield表达式的执行结果。
def my_coroutine():
while True:
receive = yield
print(receice)
it= my_coroutine()
next(it)
it.send('First')
it.send('Scenod')
-
考虑用concurrent.futures来实现真正的平行计算
-
用functools.wrpas定义函数装饰器
-
考虑以contextlib和with来改写可服用的finally代码
-
使用copyreg实现可靠的pickle
-
使用datetime模块来处理本地时间,而不是用time模块、
-
使用内置算法和数据结构
-
在重视精确度的场合,应该使用decimal
-
学会安装由python开发者社区所构建的模块
-
为每个函数、类和模块编写文档字符串
-
用包来安排模块,并提供稳固的API
-
为自编的模块定义根异常,以便将调用者与API隔离
-
用适当的方式打破循环依赖关系
-
用虚拟环境隔离项目,并重建其依赖关系
-
考虑用模块级别的代码来配置不同的部署环境
-
通过repr字符串来输出调试信息
-
用unittest来测试全部代码
-
考虑使用pdb实现交互调试
-
先分析性能,然后再优化
-
用tracemalloc来掌握内存的使用及泄露情况