当前位置: 移动技术网 > IT编程>脚本编程>Python > python编程规范系列--建议08~18

python编程规范系列--建议08~18

2019年01月19日  | 移动技术网IT编程  | 我要评论

乐文屋,华旗皇冠,语音神话网

  本系列来自《编写高质量代码 改善python程序的91个建议》的读书笔记整理。

   本章主要内容

建议8:利用assert语句来发现问题
建议9:数据交换值时不推荐使用中间交换变量
建议10:充分利用lazy evaluation的特性
建议11:理解枚举替代实现的缺陷
建议12:不推荐使用type来进行类型检查
建议13:尽量转换为浮点类型再做除法
建议14:警惕eval()的安全漏洞
建议15:使用enumerate()获取序列迭代的索引和值
建议16:分清==与is的适用场景
建议17:考虑兼容性,尽可能使用unicod
建议18:构建合理的包层次来管理module

建议8:利用assert语句来发现问题

    1)__debug__的值默认为true,且只读,无法修改(py2.7)。
    2)断言是有代价的,对性能产生一定影响。禁用断言的方法是在运行脚本的时候加上-o标记(不优化字节码,而是忽略与断言相关的语句)。
    使用断言注意点:
    1)不要滥用,这是使用断言的最基本的原则;
    2)如果python本身的异常能够处理就不要再使用断言;
    3)不要使用断言来检查用户的输入;
    4)在函数调用后,当需要确认返回值是否合理时可以使用断言;
    5)当条件时业务逻辑继续下去的先决条件时,可以使用断言。

建议9:数据交换值时不推荐使用中间交换变量

1 >>> from timeit import timer
2 >>> timer('temp=x;x=y;y=temp','x=2;y=3').timeit()
3 0.03472399711608887
4 >>> timer('x,y=y,x','x=2;y=3').timeit()
5 0.031581878662109375

建议10:充分利用lazy evaluation的特性

    lazy evaluation常被译作“延时计算”或“惰性计算”,指的是仅仅在真正需要执行计算的时候才计算表达式的值。典型例子:生成器表达式。
    1)避免不必要的计算,带来性能上的提升;
    2)节省空间,使用无限循环的数据结构成为可能。

建议11:理解枚举替代实现的缺陷

    1)替代方法:使用类属性;借助函数;使用collections.namedtuple.
1 >>> from collections import namedtuple
2 >>> seasons=namedtuple('seasons','spring summer autumn winter')._make(xrange(4))
3 >>> print seasons
4 seasons(spring=0, summer=1, autumn=2, winter=3)
5 >>> print seasons.autumn
6 2
    2)替代缺陷:允许枚举值重复;支持无意义的操作.
1 >>> seasons._replace(spring=2) # 不合理
2 seasons(spring=2, summer=1, autumn=2, winter=3)
3 >>> seasons.summer+seasons.autumn == seasons.winter # 无意义
4 true
    3)py2.7的替代方案(py3.4后引入enum类型):flufl.enum
 1 from flufl.enum import enum
 2 
 3 
 4 class seasons(enum):
 5     spring = "spring"
 6     summer = 2
 7     autumn = 3
 8     winter = 4
 9 
10 seasons = enum('seasons', 'spring summer autumn winter')
11 print seasons
12 print seasons.summer.value    

建议12:不推荐使用type来进行类型检查

    1)基于内建类型扩展的用户自定义类型,type函数并不能准确返回结果;
    2)在旧式类中,所有类的实例的type值都相等。
    3)可以用isinstance()函数检查。

建议13:尽量转换为浮点类型再做除法

        当涉及除法运算的时候尽量先将操作数转换成浮点类型再做运算。
        浮点数不精确性导致的无限循环:
1 >>> i=1
2 >>> while i!=1.5:
3 ... i=i+0.1
4 ... print i

建议14:警惕eval()的安全漏洞

 1 # -*-coding:utf-8 -*-
 2 
 3 import sys
 4 from math import *
 5 
 6 
 7 def expcalcbot(string):
 8     try:
 9         print 'your answer is', eval(string)
10     except nameerror:
11         print "the expression you enter is not valid."
12 
13 
14 while true:
15     print 'please enter a number or operation. enter e to complete. '
16 
17     inputstr = raw_input()
18     if inputstr == 'e':
19         sys.exit()
20     elif repr(inputstr) != ' ':
21         expcalcbot(inputstr)

输入:__import__("os").system("dir")   显示当前目录下的所有文件.

        __import__("os").system("del */q")   删除当前目录下的所有文件.
        因此,在实际应用过程中国呢如果使用对象不是信任源,应该尽量避免使用eval,在需要使用eval的地方可以用安全性更好的ast.literal_eval替代。

建议15:使用enumerate()获取序列迭代的索引和值

        注意,在获取迭代过程中字典的key和value,应该使用如下iteritems()方法。
1 >>> person={'name': 'josn', 'age': 19, 'hobby': 'football'}
2 >>> for k,v in person.iteritems():
3 ... print k, ":", v

建议16:分清==与is的适用场景

 1 >>> a="hi"
 2 >>> b="hi"
 3 >>> a is b
 4 true
 5 >>> a==b
 6 true
 7 >>> a1 ="i am using long string for testing" # 注意区分
 8 >>> b1 ="i am using long string for testing"
 9 >>> a1 is b1
10 false
11 >>> a1==b1
12 true

    is:表示的是对象标识符,检查对象的标识符是否一致,也就是比较两个对象在内存中是否拥有同一块内存空间;
    ==:表示的是值相等,用来判断两个对象的值是否相等,可以被重载。
    字符串驻留(string interning)机制:对于较小的字符串,为了提高系统性能会保留其值的一个副本,当创建新的字符串时直接指向该副本即可。

建议17:考虑兼容性,尽可能使用unicode

    python内建的字符串有两种类型:str和unicode,共同祖先为basestring。
    windows本地默认编码是cp936。
    解码:str.decode([编码参数[,错误处理]])  
    编码:str.encode([编码参数[,错误处理]])
    错误处理参数有3种方式:
        (1)strict:默认值,抛出unicodeerror异常;
        (2)ignore:忽略不可转换的字符;
        (3)replace:将不可转换字符用?代替。
    有些软件在保存utf-8编码时,会在文件最开始地方插入不可见的bom,可以利用codecs解决。
1 import codecs
2 
3 
4 content = open('manage.py', 'r').read()
5 
6 if content[:3] == codecs.bom_utf8:
7     content = content[:3]
8 
9 print content.decode("utf-8")
    编码声明的三种方式:
1 # coding=<encoding name> #方式一
2 #!/usr/bin/env python
3 
4 # -*- coding:<encoding name> -*- #方式二
5 
6 #!/usr/bin/env python
7 # vim:set fileencoding=<encoding name> #方式三

建议18:构建合理的包层次来管理module

    包中__init__.py文件的作用:1)使包和普通目录区分;
              2)在该文件中声明模块级别的import语句从而使其变成包级别可见;
              3)通过该文件中定义__all__变量,控制需要导入的子包或者模块。
    使用包的好处:
    1)合理组织代码,便于维护和使用;
    2)能够有效地避免名称空间冲突。

如对本文有疑问,请在下面进行留言讨论,广大热心网友会与你互动!! 点击进行留言回复

相关文章:

验证码:
移动技术网