A sentence A picture A day!

Python 味道[2]

利用assert语句来发现问题

assert expression1 [",",expression2]

依据expression1会返回True或者False,值为False时引发AssertionError,expression2可选,用于传递具体的异常信息

注意:

  • python不像C/C++,没有严格定义调试和发布模式。禁用断言:在运行脚本是加上-O标志
  • python本身的异常能够处理就不要再使用断言【比如数组越界、类型不匹配、除数为0】
  • 不用断言检查用户输入。较好的做法是使用条件判断,不符合输出错误提示信息
  • 在函数调用后,当需要确认返回值是否合理时可以使用断言。
  • 当条件是业务逻辑继续下去的先决条件时可以使用断言。

数据交换值时不推荐使用中间变量

在python中直接用

>>> x,y = y,x

充分利用Lazy evaluation

Lazy evaluation仅仅在真正需要执行的时候才计算表达式的值

  • 避免不必要计算。在if x and y,x为false情况下将不再计算y;if x or y,x为true不再计算y。因此对于or应将真值可能性高的变量写在前。
  • 节省空间,使无限循环成为可能。典型的使用延迟计算的例子是生成器表达式,尽在每次需要计算的时候才通过yield产生元素。

    def fib():
        a,b=0,1
        while True:
            yield a
            a,b=b,a+b
    
    print list(islice(fib(),5))
    

尽量转换为浮点类型再做除法

当涉及除法运算时尽量将操作数转换为浮点类型在做运算

>>>g=float((4*96+3*85))/float(((4+3+2)*100))

对于浮点数的处理,其计算结果可能并不是完全准确的。对于在while中使用i!=1.5更要避免,浮点数的比较最好能够指明精度

晶体eval()的安全漏洞

Python中eval()函数将字符串str当成有效的表达式来求值并返回计算结果

函数声明 eval(expression[,global[,local]])

“eval is evil”针对的是eval()的安全性,当用户输入了不安全的字符串将造成不良后果。如果使用对象不是信任源,应尽量避免使用eval,可用安全性更好的ast.literal_eval替代【木有试过:P】

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

list1=['a','b','c']
for i,e in enumerate(list1):
    print "index:",i,"element:",e

函数enumerate()主要为了解决在循环中获取索引以及对应值问题

enumerate(sequence,start=0)

sequence可以为序列,list、set等,函数的返回本质上是一个迭代器,可用next()方法获取下一个迭代元素

>>>e=enumerate(list1)
>>>e.next()

enumerate()函数实现

def enumerate(sequence,start=0):
    n=start
    for elem in sequence:
        yield n,elem
        n+=1

plus,要获取迭代过程中字典的key和value,应使用iteritems()方法

infodict=['name':'reindeer','age':'25']
for k,v in infodict.iteritems():
    print k,":",v

is与==的适用场景

操作符 意义
is object identity 对象是否一致 同一块内存空间
== equal 检验对象值是否相等

编码编码呀,尽可能使用Unicode

关于文件的编码问题深有感触呀~~

Python内建的字符串两种类型:str和Unicode,公共祖先basestring。

最早的ASCII编码用一个字节8bit。我国表示汉字编码GBK。 》》》Problem:不同编码系统之间存在冲突 》》》solve:为不同的文字分配同一编码

Unicode编码系统可分为编码方式和实现方式两个层次。编码方式分为UCS-2(两个字节)和UCS-4(四个字节)。实现方式简称UTF包括UTF-7、UTF-16、UTF-32、UTF-8等

Unicode编码(十六进制) UTF-8字节流(二进制)
000000~00007F 0xxxxxxx
000080~0007FF 110xxxxx 10xxxxxx
000800~00FFFF 1110xxxx 10xxxxxx 10xxxxxx
010000~10FFFF 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx

Python处理中文字符常遇见的问题

  • 读出文件内容为乱码
  • 当Python源文件中包含中文字符时抛出SyntaxError异常【Non-ASCII charater ‘\xxx’ in……】
  • 普通字符和Unicode进行字符串连接时抛出UnicodeDecodeError异常

    #coding=utf-8
    s = "中文"+ u"Chinese"
    print s
    

    抛出异常UnicodeDecodeError:‘ascii’ codec can’t decode byte 0xd6 in position 0:ordinal not in range(128)

对应上述问题:

  • 读入的文件是用UTF-8编码形式保存的【Windows本地默认编码是CP936,被映射为GBK】,当在控制台上直接显示UTF-8时,两种编码不兼容。要解决一的问题可以使用Unicode作为中间媒介来完成转换。首先对读入的字符用UTF-8进行解码,再用GBK进行编码

    >>>fhandle = open("t.txt",'r')
    >>>print (fhandle.read().decode("utf-8")).encode("gbk"))(1)
    >>>fhandle.close()
    

    decode方法将其他编码对应的字符串解码成Unicode,encode为编码

    str.decode([编码参数[,错误处理]])
    str.encode([编码参数[,错误处理]])
    

    编码参数

    编码参数
    ‘ascii’
    ‘latin-1’ or ‘iso-8859-1’
    utf-8
    utf-16
    错误处理参数三种方式
    错误处理参数 处理方式
    strict 默认处理方式,抛出UnicodeError异常
    ignore 忽略不可转换字符
    replace 将不可转换的字符用?代替

    plus,某些情况下 (1)会出现如下异常 UnicodeDecodeError:‘gbk’ codec can’t encode charcter u’\uxxxx’ in position0:illegal multibyte sequence——某些软件在保存UTF-8编码时在文件最开始的地方插入不可见字符BOM(0xEF 0xBB 0xBF)这些不可见字符无法被正确解析—–利用codecs模块可以处理这种问题

    import codesc
    content = open("t.txt",'r').read()
    if content[:3] == codecs.BOM_UTF*
    content = content[3:]
    

    我记得貌似有直接用codecs打开文件的方式,用codecs提供的open方法来指定打开的文件的语言编码bfile = codecs.open("dddd.txt",'r',"UTF-8" )

  • 对于问题二:Pyhton中默认的编码为ASCII(sys.getdefaultencoding()),文件**.py是以ASCII形式保存的。中文字符不是ASCII,源文件中未指定其他编码方式。因此,要在源文件中进行编码声明

    #codnig=utf-8
    or
    #!/usr/bin/python
    #!-*- coding: utf-8 -*-
    or
    #!/usr/bin/python
    # vim:set fileencoding=utf-8 :
    
  • 对于问题三:+左边为中文,类型为str,右边为Unicode字符串。连接时,Python将左边的中文转为Unicode再与右边的Unicode连接,将str转为Unicode事使用系统默认的ASCII进行解码,当编码值大于128时,不能正确处理。解决办法: 1)指定str转为Unicode时的编码方式s = "中文".decode('gbk')+u"Chinese";2)将Unicode字符串进行UTF-8编码 `s = “中文”+u”Chinese”.encode(“utf-8”)

Unicode提供了不同编码系统之间字符转换的桥梁,要弄清字符所采取的编码方式以及正确的解码方法。对于中文字符,建议直接使用Unicode表式方式s = u"hao可爱的小鹿"。pyhton2.6后可通过import unicode_literals自动将定义的普通字符识别为Unicode字符串

构建合理的报层次来管理module

本质上每一个Python文件都是一个模块。但是将所有Python文件放在一个目录下并不好,需要合理组织项目的层次来管理模块—包(package) 包,类似目录,包除了常规的Python文件(模块)以外,还包含init.py文件,同时它允许嵌套,包结构如下:

Package/ __init__.py
    Modu1.py
    Modu2.py
    Subpackage/ __init__.py
        Modu1.py
        Modu2.py

包中模块通过“.”访问。例如Package.Modu1;Package.Subpackage.Modu2。 导入方法:

  • 直接导入一个包

    import Package
    
  • 导入子模块或子包

    from Package import Modu1
    or
    import Package.Modu1
    
    from Package import Subpackage
    or
    import Package.Subpackage
    
    from Package.Subpackage import Modu1
    or
    import Package.Subpackage.Modu1
    

__init__.py文件的作用—1)与普通目录的区分;2)申明模块级别的import语句从而使其变成包级别可见。

在__init__.py文件中添加from Modu1 import Test【Test为Package下Modu1中得类】可直接导入类Test。如果__init__.py文件为空,当想使用from Package import * 导入所有模块时将不能生效。

__init__.py另一个作用通过定义__all__变量,控制需要导入的子包或者模块。

在Package目录下的__init__.py文件中添加:
__all__ = ['Mode1','Modu2','Subpackage']

运行from Package import * ,__all__变量中定义的模块和包被导入当前的名字空间

包——

  • 合理组织代码

    Proj/
    |---README
        |----LICENSE
        |----setup.py
        |-----requirements.txt
        |-----sample/
        |   |----__init__.py
        |   |----core.py
        |   |----help.py
        |------docs/
        |   |------conf.py
        |   |------index.rst
        |------bin/
        |------package/
        |   |-----__init__.py
        |   |------sunpackage/
        |   |------......
        |------tests/
        |   |------test_basic.py
        |   |------test_advanced.py
    
  • 避免名称空间的冲突

ATTENTION:这里的包与后面的软件包不同,这里的仅限于包含一个或一系列Python文件,为了合理组织代码。