编写高质量Python代码应该注意的知识点

编写高质量Python代码

摘自 《编写高质量代码改善 Python 程序的 91 个建议》

使用with自动关闭资源

上下文管理器(context manager)

在对象中定义 __enter__()__exit__()方法

__enter__():进入运行时的上下文,返回运行时上下文相关的对象,with语句会叫这个返回值绑定到目标对象。

__exit__(exception_type, exception_value, traceback):退出运行时的上下文,定义在块执行(或终止)之后上下文管理器应该做什么。可以处理异常、清理现场或者处理处理with语句执行完成之后需要处理的动作。

Python中提供的contextlib模块

contextlib模块通过生成器实现,其中的contextmanager作为装饰器来提供一种针对函数级别上的上下文管理机制。可直接作用于函数/对象而不用关心__enter__()__exit__()方法的具体实现。

使用else子句简化代码

循环语句

当循环自然终结(循环条件为假)时else从句会被执行一次,而当循环是由break语句中断时,else子句不会被执行。

栗子:

def print_prime(n):
    for i in range(2, n):
        found = True
        for j in range(2, i):
            if i % j == 0:
                found = False
                break
        if found:
            print('%d is a prime number'%i)
def print_prime2(n):
    for i in range(2, n):
        for j in range(2, i):
            if i % j  == 0:
                break
        else:
            print('%d is a prime number')

以上两个函数的执行完全一样。

异常处理

Python的异常处理中有一种try-except-else-finally形式。else子句在try无异常时执行。

举栗:

def save(db, obj):
    # some_error_occurred = False
    try:
        db.execute('a sql stmt', obj.attr1)
        db.execute('a sql stmt2', obj.attr2)
    except DBError:
        db.rollback()
    else:
        db.commit()

如果没有else子句,就要通过异常标识来判断是否进行db.commit()

异常处理

异常处理流程

在异常语句中,except异常捕获会出现多次,else子句在没有异常时执行,finally子句不管有没有异常都会执行。

其中,在except语句和else语句中再有异常产生时,会继续执行finally语句;而finally中继续有异常发生,会向上层抛出,处理不当会导致前面抛出的异常丢失。

异常处理遵循的原则

  1. 注意异常的粒度,不推荐在try中放入过多的代码。注意保持异常粒度的一致性和合理性。
  2. 谨慎使用单独的except语句处理所有异常,最好能定位具体异常。单独的except语句的使用,真实的错误往往被掩盖。
  3. 注意异常捕获的顺序,在合适的层次处理异常。应该将子类异常在前面的except语句中抛出,父类异常在后面的except语句抛出。Python中使用BaseException作为所有异常的基类。
  4. 使用更为友好的异常消息,遵循异常参数的规范。根据异常阅读者(开发者/用户),选择合适的异常消息。

Python中的内建异常继承结构

finally中可能发生的陷阱

未被处理的异常会被临时保存起来,当finally执行完毕的时候,临时保存的异常将会再次被抛出。但如果finally语句中产生了新的异常或者执行了return或者break语句,那么临时保存的异常将会被丢失,从而导致异常屏蔽

对于有返回语句的异常处理,如果存在finally语句,那么在执行return之前,会先执行finally中的语句,此时如果finally语句中return语句,则前边的return语句会被屏蔽。

开发过程中,应该避免在finally语句中使用break和return语句。

判断对象是否为空

Python中为空的对象:

  • 常量 None,False
  • 任何形式的数值类型零,如0,0L,0.0,0j
  • 空的序列,如(),[],空字符串
  • 空的字典,如{}
  • 当用户定义的类中定义了__nonzero__()方法和__len__()方法,并且该方法返回整数0或者布尔值False。

其中常量None的特殊性体现在它既不是0,False,也不是空字符串,就是一个空值对象。其数据类型为NoneType,遵循单例模式,是唯一的。所有赋值为None的变量都相等,None与任何其他非None对象比较结果都为False。

注:float(‘nan’)为True。

自定义对象的非空判断

__nonzero__()方法用于对自身对象进行空值测试,返回0/1或者True/False。如果一个对象没有定义该方法,Python将获取__len__()方法调用的结果来进行判断,__len__()返回值为0则表示为空。

如果一个类中既没有定义__len__()方法也没有定义__nonzero__(),该类的实例用if判断的结果都为True。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值