effective python学习笔记

这篇博客探讨了Python编程的一些有效做法,包括遵循PEP8风格指南,避免单行语句,理解字节、字符串与Unicode的区别,以及合理使用列表推导式、生成器和异常处理。还提到了元类、并发处理、模块组织和调试工具的使用,旨在提升代码质量和效率。
摘要由CSDN通过智能技术生成
  1. 确认自己所使用的python版本

  2. 遵循PEP8风格指南
    函数、变量及属性应该用小写字母来拼写,各单词之间以下划线相连,例lowercase_underscore.
    类与异常:每个单词均大写的形式来命名,例如CaoutlizedWord.
    不要编写单行的if语句、for循环、while循环以及except语句
    不要通过检测长度的办法来判断somelist是否为[] ,而应该采用 if not somelist这种形式。

  3. 了解byte、str与unicode的区别

  4. 用辅助函数来取代复杂的表达式

  5. 了解切割序列的办法

  6. 在单次切片操作内,不要同时指定start、end和stride

  7. 用列表推导式来取代map和filter

  8. 不要使用含有两个以上表示的列表推导

  9. 用生成器表达式来改写数据量较大的列表推导

  10. 尽量使用enumerate取代range
    enumerate将各种迭代器包装为生成器,以便稍后产生输出值。

for i, flavor in enumerate(flavor_list):
    print(i,flavor)

还可以值得enumerate开始计数的值enumerate(flavor_list)

  1. 用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就会出现奇怪的行为。

  1. 不要在for和while循环后面写else块

  2. 合理利用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())     
  1. 尽量用异常来表示特殊情况,而不要返回None

  2. 了解如何在闭包里使用外围作用域中的变量(不太明白)

  3. 考虑用生成器来改写直接返回列表的函数

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))
  1. 在参数上面迭代时,要多加小心。

​ 如果函数接受的参数是个对象列表,那么很有可能在这个列表上迭代。

  1. 用数量可变的位置参数减少视觉杂讯

就是使用*args

  1. 用关键字参数表表达可选的行为

例如sort(reverse=True)

  1. 用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={}
    
  1. 用只能以关键字形式指定的参数来保证代码清晰

  2. 尽量用辅助类来维护程序的状态,而不要用字典和元组(不太明白)

  3. 简单的接口应该接受函数,不是类的实例(也是不太明白)

  4. 以@classmethod形式的多态去通用地构建对象(人又看迷糊了)

​ 类的多态

  1. 用super初始化父类

​ 初始化父类的传统方式,是在子类中用子类实例直接调用父类的__init__方法。

问题:1.如果子类收到了多重继承的影响,那么直接调用超类的__init__方法,可能会产生无法预知的结果。

  1. 只在使用Mix-in组件制作工具时使用多重继承(尽量别用,不去深究了)

  2. 多用public属性,少用private属性

  3. 继承collections.abc以实现自定义的容器类型

  4. 用纯属性取代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方法
 
  1. 考虑用@property来代替属性重构(感觉我目前不太用得着)

  2. 用描述符来改写需要复用的@property方法

  3. __getattr__ __getattrbute__和__setattr__实现按需生成的属性。

  4. 用元类来验证子类

元类最简单的一种用途,就是验证某个类定义是否正确。

  1. 用元类来注册子类

  2. 用元类来注解类的属性

  3. 用subprocess来管理子进程

  4. 可以用线程来执行阻塞式IO,但不要他来进行平行计算。

  5. 在线程中使用Lock来防止数据竞争

  6. 用Queue来协调各线程之间的工作

  7. 考虑用协程来并发地执行多个函数

协程的工作原理:每当生成器函数执行到yield表达式的时候,消耗生成器的那段代码。就通过send方法给生成器回传一个值。而生成器在收到经由send函数所传进来的那个值之后,会将其视为yield表达式的执行结果。

def my_coroutine():
	while True:
    receive = yield
    print(receice)
    
it= my_coroutine()
next(it)
it.send('First')
it.send('Scenod')
  1. 考虑用concurrent.futures来实现真正的平行计算

  2. 用functools.wrpas定义函数装饰器

  3. 考虑以contextlib和with来改写可服用的finally代码

  4. 使用copyreg实现可靠的pickle

  5. 使用datetime模块来处理本地时间,而不是用time模块、

  6. 使用内置算法和数据结构

  7. 在重视精确度的场合,应该使用decimal

  8. 学会安装由python开发者社区所构建的模块

  9. 为每个函数、类和模块编写文档字符串

  10. 用包来安排模块,并提供稳固的API

  11. 为自编的模块定义根异常,以便将调用者与API隔离

  12. 用适当的方式打破循环依赖关系

  13. 用虚拟环境隔离项目,并重建其依赖关系

  14. 考虑用模块级别的代码来配置不同的部署环境

  15. 通过repr字符串来输出调试信息

  16. 用unittest来测试全部代码

  17. 考虑使用pdb实现交互调试

  18. 先分析性能,然后再优化

  19. 用tracemalloc来掌握内存的使用及泄露情况

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值