VII Python(5)基础知识(模块、包、异常)
运算符重载:
运算符重载是指在方法中拦截内置的操作(python解释器内部实现的操作,如__add__、__contains__、__delitem__、__eq__、__ge__等等这些都是运算符),当类的实现出现在内置操作中,python会自动调用自定义的方法,并且返回自定义方法的操作结果;
运算符重载让类拦截常规的python运算;
类可重载所有python表达式运算符;类也可以重载打印、函数调用、属性(点号运算符)等内置运算;
重载使类实例的行为像内置类型;重载通过提供特殊名称的类方法实现;
运算符重载并非必须,并且通常也不是默认的;
基于特殊的方法定制类:
除__init__和__del__(GC会自动实现,__del__可不用)之外,python类支持使用许多的特殊方法;
特殊方法都以双下划线开头和结尾,有些特殊方法有默认行为,没有默认行为的是为了留到需要的时候再实现;
这些特殊方法是python中用来扩充类的强大工具,它们可以实现(模拟标准类型、重载操作符);
特殊方法允许类通过重载标准操作符(+、*),甚至包括分段下标及映射操作([])来模拟标准类型;
__init__(构造函数,对象建立x=Class(args));
__del__(析构函数,x对象回收);
__add__(运算符+,如果没有_iadd_,x+y,x+=y);
__or__(运算符|、OR位或,如果没有_ior_,x|y,x|=y);
__repr__,__str__(打印、转换,pirnt(x),repr(x),str(x));
__call__(函数调用,x(*args,**keys);
__getattr__(点号运算,x.undefined);
__setattr__(属性赋值语句,x.arg=value);
__delattr__(属性删除,del x.arg);
__getattribute__(属性获取,x.arg);
__getitem__(索引运算,x[key],x[i:j],没有__iter__时的for循环和其它迭代器);
__setitem__(索引赋值语句,x[key]=value,x[i:j]=sequence);
__delitem__(索引和分片删除,del x[key],delx[i:j]);
__len__(长度,len(x),如果没有__bool__真值测试);
__bool__(布尔测试,bool(x),真测试在python2.6中叫__nonzero__);
__lt__、__gt__、__le__、__ge__、__eq__、__ne__(特定的比较,x<y,x>y,x<=y,x>=y,x==y,x!=y,在python2.6中只有__comp__);
__radd__(实地增强的加法,x+=y或else __add__);
__iter__、__next__(迭代环境,I=iter(x),next(I);for loops,inif no __contains,all comprehensions,map[F,X],__next__;在python2.6中称为next);
__contains__(成员关系测试,item in x,任何可迭代的);
__index__(整数值,hex(x)、bin(x)、coct(x)、o[x]、o[x:],替代python2中的__oct__、__hex__);
__enter__、__exit__(环境管理器,withobj as var:);
__get__、__set__、__delete__(描述符属性,x.attr,x.attr=value,del x.attr);
__new__(创建,在__init__之前创建对象);
编程(了解算法、数据结构、设计模式)
可调用对象(运算符为(),__call__(),函数(内置函数__builtin__、自定义函数有def和lambda定义的)、类、类方法(类中定义的函数通常有self));
函数的属性(__doc__、__name__、__dict__、__code__、__globals__全局匿名空间的字典)
方法的属性(__doc__、__name__、__class__方法所属的类、__func__实现读方法的函数对象、__self__调用此方法的实例);
内置函数属性(__doc__、__name__、__self__);
类(__doc__、__name__、__bases__、__dict__、__module__定义了当前类的模块名称);
实例(__class__、__dict__);
对象都有特殊方法(__init__、__new__、__del__、__dir__、__add__、__ge__);
模块:
可将代码量大的程序分割成多个有组织的,彼此独立但又能相互交互的代码片段,这些自我包含的有组织的代码段就是模块;
模块在物理形式上表现以.py为结尾的文件;
一个文件被看作是一个独立的模块,一个模块也可被看作是一个文件;模块的文件名就是模块的名字加上扩展名.py;
每个模块都有自己的名称空间,python允许导入其它模块以实现代码重用,从而也实现了将独立的代码文件组织成更大的程序系统;
python中模块也是对象,在一个模块的顶层定义的所有变量都在被导入时成为了被导入模块的属性;
python程序架构:
一个python程序通常包括一个顶层文件和其它的(0个、1个或多个)模块文件;
顶层文件(包含了程序的主要控制流程);
模块文件(为顶层文件或其它模块提供各种功能性组件);
模块首次导入(或重载)时python会立即执行模块文件的顶层程序代码(不在函数内的代码,例如会执行赋值语句和def语句而def语句内部的代码不执行,只有在方法被调用时才会执行),而位于主体内的代码直到函数被调用时才会执行;
模块的执行环境:
模块是被导入的,但模块也可导入和使用其它模块(链式关系),这些模块可以用python或其它编程语言写成;
模块可内含变量、函数及类来进行工作,而函数和类可以包含变量和其它元素;
导入模块:
导入模块时只能使用模块名不能带.py;
import语句(导入指定的整个模块,包括生成一个以模块名命名的名称空间,例如list.pop()和dict.pop()是在不同的名称空间),语法:
import module1[,module2[,module3,...]]
import module as module_alias(别名是自定义的名称空间,一旦定义只能使用别名调用)
from...import语句(常用于导入指定模块的部分属性至当前名称空间),语法:
from module import name1[,name2[,...nameN]]
注:
import和from...import是赋值语句,import和from是可执行语句,类似def,因此它们可以嵌套在if测试中,出现在def中等等;
python执行到这些语句时才会对其进行解析,意味着,所有来自模块的属性仅在import语句执行后才能使用;
import和from都是都是隐性赋值语句,import将整个模块对象赋值给一个变量名,from将一个或多个变量名赋值给导入此模块中的同名对象;
模块就是名称空间,模块的名称空间可通过属性__dict__或dir()获取,通过点运算符获取,如MODULE.ATTRIBUTE;
模块是一个独立的作用域(本地变量就是全局变量);
import的工作机制,导入模块时执行三个步骤:
找到模块文件(在指定的路径下搜索模块文件);
编译成字节码bytecode(文件导入时就会编译,因此顶层文件的.pyc字节码文件在内部使用后会被丢弃,只有被导入的文件才会留下.pyc这个文件);
执行模块的代码来创建其所定义的对象(模块文件中的所有语句会依次执行,从头至尾,而此步骤中任何对变量名的赋值运算都会产生所得到的模块文件的属性);
注:模块只在第一次被导入时才执行以上三步,后续的导入操作只不过是提取内存中已加载的模块对象;reload()可用于重新加载模块
模块搜索:
python解释器在import模块时必须先找到对应的模块文件:
模块代码中的if __name__='__main__':语句用于测试;
sys.path所包含的路径,四处:程序的主目录(即当前目录);PYTHONPATH目录(如果设置了此变量);标准链接库目录;任何NaNh文件的内容(如果存在NaNh文件);
python会选择在搜索路径中的第一个符号导入文件名的文件;
sys.path.append('/tmp/python2.7/lib')
python包:
包用于将一组模块归并到一个目录中,此目录即为包,目录名即为包名;
包是一个有层次的文件目录,它定义了一个由模块和子包组成的python应用程序执行环境;
基于包,python在执行模块导入时可以指定模块的导入路径,如import dir1.dir2.module;
如上图:要使用package1,则py_pkg_mod容器必须要在模块搜索路径中,则可以import package1.mod1
包导入语句的路径内的每个目录中都必须有__init__.py文件,__init__.py文件中可包含python代码,但通常为空,仅用于扮演包初始化时的挂钩、替目录产生模块命名空间以及使用目录导入时实现from *行为的角色;
举例:
[root@localhost ~]# mkdir -p /tmp/python2.7/lib #(此目录要在搜索路径中,使用sys.path.append('/tmp/python2.7/lib')添加)
[root@localhost ~]# cd !$
cd /tmp/python2.7/lib
[root@localhost lib]# mkdir pkg1
[root@localhost lib]# cd pkg1
[root@localhost pkg1]# touch __init__.py
[root@localhost pkg1]# vim test.py
------------------------script start--------------------
#!/usr/bin/python2.7
#
from distutils.core import setup
setup(
name = 'test',
version = '0.0.1',
author = 'MagEdu',
author_email = 'magedu@foxmail.com',
py_modules =['test'],
url = 'http://www.magedu.com',
description = 'a simple module',
)
----------------------script end-------------------
[root@localhost pkg1]# ipython
……
In [1]: import sys
In [2]:sys.path.append('/tmp/python2.7/lib')
In [3]: sys.path
Out[3]:
['',
'/usr/local/python2.7/bin',
'/usr/local/python2.7/lib/python27.zip',
'/usr/local/python2.7/lib/python2.7',
'/usr/local/python2.7/lib/python2.7/plat-linux2',
'/usr/local/python2.7/lib/python2.7/lib-tk',
'/usr/local/python2.7/lib/python2.7/lib-old',
'/usr/local/python2.7/lib/python2.7/lib-dynload',
'/usr/local/python2.7/lib/python2.7/site-packages',
'/usr/local/python2.7/lib/python2.7/site-packages/IPython/extensions',
'/root/.ipython',
'/tmp/python2.7/lib']
In [5]: import pkg1.test
In [6]: pkg1.test.testFunc
pkg1.test.testFunc
模块的顶层执行及被导入:
一个模块文件可以同时支持顶层执行(作为顶层文件)或被导入(作为模块文件);
每个模块都有个名为__name__的内置属性,python会自动设置该属性;
如果文件是以顶层程序文件执行,在启动时__name__的值为__main__,如果被导入则__name__的值为模块名,可以在模块文件中检测自己的__name__属性,以实现在执行时运行指定的代码,常用于模块的自我测试;
发布python模块或程序:
python模块、扩展和应用程序可以按以下几种方式进行打包和发布:
压缩文件,使用distutils,win的zip文件和类Unix平台的.tar.gz文件源码;
自动解包或自动安装可执行文件,如win的.exe文件;
自包含的,不要求安装的预备运行可执行程序,如win的.exe文件,Unix上带有一个小的脚本前缀的ZIP压缩文件,Mac上的.app文件等;
平台相关的安装程序,如win的.msi文件,Linux上常见的.rpm、.src.rpm、.deb文件等;
python eggs,较流行的第三方扩展;
distutils模块能帮助完成模块或程序发布;
发布是指一个文件集合,这些文件联合在一起可使用distutils构建、打包和发布模块;
创建好的发布可用于安装,也可上传到PyPi与他人共享;
创建发布(将各代码文件组织到模块容器中,准备README或README.txt文件,而后在容器中创建setup.py文件);
setup.py的常用参数,大体可分为元数据信息和包中的内容列表:
name(包的名称,必须);
Version(版本号,必须);
author(作者名称);
author_email(作者的邮件地址);
maintainer(维护者的名称)
maintainer_email;
url(包的主页);
description(包的简短描述);
long_description(包的详细描述);
download_url(包的下载位置);
Classifiers(字符串分类器列表);
py_modules(所有模块的列表,后跟的是列表,多个模块用逗号分隔,这些模块可能位于包的根目录下(各子包名组成的列表这一级别,modname),也可能位于某子包中(subpkg.modname));
platforms(适用平台列表);
license(许可证);
packages(各子包组成的列表);
python setup.py --help
python setup.py --help-commands
python setup.py sdist|bdist --help
python setup.py sdist|bdist --help-formats
[root@localhost pkg1]# python2.7 setup.py --help-commands
Standard commands:
build build everythingneeded to install
build_py "build"pure Python modules (copy to build directory)
build_ext build C/C++extensions (compile/link to build directory)
build_clib build C/C++libraries used by Python extensions
build_scripts "build"scripts (copy and fixup #! line)
clean clean uptemporary files from 'build' command
install installeverything from build directory
install_lib install allPython modules (extensions and pure Python)
install_headers install C/C++header files
install_scripts install scripts(Python or otherwise)
install_data install datafiles
sdist create a sourcedistribution (tarball, zip file, etc.)
register register the distribution with the Pythonpackage index
bdist create a built(binary) distribution
bdist_dumb create a"dumb" built distribution
bdist_rpm create an RPMdistribution
bdist_wininst create anexecutable installer for MS Windows
upload upload binarypackage to PyPI
check perform somechecks on the package
usage: setup.py [global_opts] cmd1[cmd1_opts] [cmd2 [cmd2_opts] ...]
or: setup.py --help [cmd1 cmd2 ...]
or: setup.py --help-commands
or: setup.py cmd --help
[root@localhost pkg1]# python2.7 setup.py bdist --help-formats
List of available distribution formats:
--formats=rpm RPMdistribution
--formats=gztar gzip'ed tar file
--formats=bztar bzip2'ed tarfile
--formats=ztar compressed tarfile
--formats=tar tar file
--formats=wininst Windowsexecutable installer
--formats=zip ZIP file
--formats=msi MicrosoftInstaller
[root@localhost pkg1]# python2.7 setup.py sdist --help-formats
List of available source distributionformats:
--formats=bztar bzip2'ed tar-file
--formats=gztar gzip'ed tar-file
--formats=tar uncompressed tarfile
--formats=zip ZIP file
--formats=ztar compressed tarfile
python setup.py build(安装第三方模块时,默认会在当前目录下创建build/,若要在其它目录下创建,使用python setup.py --build-base=/path/to/build_dir,可保证源码的整洁,同时在build/下可能会创建lib/(保存python编写的程序)和lib.platform/(存放其它语言编写的程序))
python setup.py install(安装时可以先build再install,build可省因为在install时会先build再install)
ls/usr/local/python2.7/lib/python2.7/site-package/(第三方模块的默认安装路径通常为site-package/此站点路径)
自定义安装路径:
--use= (安装至某用户家目录下,常用于非root用户);
--prefix= (与python相关的路径);
--exec-prefix= (与python无关与平台有关的编译文件路径);
注:--prefix和--exec-prefix要对指定路径有写权限
安装深度定制:
--install-purelib=/path/to/python_lib(python相关)
--install-platlib=/path/to/plat_lib(其它平台相关)
--install-lib=/path/to/lib(若此项与前两项都用了,此项优先级最高)
--install-scripts=/path/to/bin(可执行文件安装路径)
--install-data= (数据文件)
--install-headers= (头文件)
完成打包:
#python setup.py sdist [--formats=FORMAT](在要发布的目录中执行,sdist(sourcedistribution))
sdist支持的FORMAT有:zip(zip file)、gztar(.tar.gz file)、bztar(.tar.bz2file)、.ztar(.tar.z file)、tar(.tar file);
#python setup.py bdist [--formats=FORMAT](bdist(binarydistribution))
bdist支持的FORMAT有:zip、gztar、bztar、ztar、tar、rpm(RPM package)、pkgtool(solarispkgtool)、wininst(win上自解压的zip包)、msi(microsoft installer);
举例(打包发布,用sdist方式):
[root@localhost pkg1]# pwd
/tmp/python2.7/lib/pkg1
[root@localhost pkg1]# touch __init__.py
[root@localhost pkg1]# touch README.txt
[root@localhost pkg1]# vim setup.py
------------------------script start--------------------
#!/usr/bin/python2.7
#
from distutils.core import setup
setup(
name = 'test',
version = '0.0.1',
author = 'MagEdu',
author_email = 'magedu@foxmail.com',
py_modules =['test'],
url = 'http://www.magedu.com',
description = 'a simple module',
)
----------------------script end-------------------
注:#(py_modules=……若有多个模块,在列表中用逗号分隔)
[root@localhost pkg1]# ls
__init__.py __init__.pyc README.txt setup.py test.py test.pyc
[root@localhost pkg1]# python2.7 setup.py sdist
running sdist
running check
warning: sdist: manifest template'MANIFEST.in' does not exist (using default file list)
writing manifest file 'MANIFEST'
creating test-0.0.1
making hard links in test-0.0.1...
hard linking README.txt -> test-0.0.1
hard linking setup.py -> test-0.0.1
hard linking test.py -> test-0.0.1
creating dist
Creating tar archive
removing 'test-0.0.1' (and everything underit)
[root@localhost pkg1]# ls
dist __init__.py __init__.pyc MANIFEST README.txt setup.py test.py test.pyc
[root@localhost pkg1]# ls dist
test-0.0.1.tar.gz
举例(发布,用bdist):
[root@localhost pkg1]# python2.7 setup.py bdist
running bdist
running bdist_dumb
running build
running build_py
creating build
creating build/lib
copying test.py -> build/lib
installing to build/bdist.linux-x86_64/dumb
running install
running install_lib
creating build/bdist.linux-x86_64
creating build/bdist.linux-x86_64/dumb
creating build/bdist.linux-x86_64/dumb/usr
creatingbuild/bdist.linux-x86_64/dumb/usr/local
creatingbuild/bdist.linux-x86_64/dumb/usr/local/python2.7
creatingbuild/bdist.linux-x86_64/dumb/usr/local/python2.7/lib
creatingbuild/bdist.linux-x86_64/dumb/usr/local/python2.7/lib/python2.7
creatingbuild/bdist.linux-x86_64/dumb/usr/local/python2.7/lib/python2.7/site-packages
copying build/lib/test.py ->build/bdist.linux-x86_64/dumb/usr/local/python2.7/lib/python2.7/site-packages
byte-compilingbuild/bdist.linux-x86_64/dumb/usr/local/python2.7/lib/python2.7/site-packages/test.pyto test.pyc
running install_egg_info
Writingbuild/bdist.linux-x86_64/dumb/usr/local/python2.7/lib/python2.7/site-packages/test-0.0.1-py2.7.egg-info
Creating tar archive
removing 'build/bdist.linux-x86_64/dumb'(and everything under it)
[root@localhost pkg1]# ls dist
test-0.0.1.linux-x86_64.tar.gz test-0.0.1.tar.gz
[root@localhost pkg1]# cp dist/test-0.0.1.linux-x86_64.tar.gz /
[root@localhost pkg1]# cd /
[root@localhost /]# ls /usr/local/python2.7/lib/python2.7/site-packages/
IPython ipython-3.0.0-py2.7.egg-info README
[root@localhost /]# tar xf test-0.0.1.linux-x86_64.tar.gz #(若二进制包在根下,默认解压后放到python站点路径下,大多数第三方模块都在站点路径下)
[root@localhost /]# ls /usr/local/python2.7/lib/python2.7/site-packages/
IPython ipython-3.0.0-py2.7.egg-info README test-0.0.1-py2.7.egg-info test.py test.pyc
注:pip和easy_install工具的使用
python异常:
异常是python运行时错误;
语法错误(软件的结构上有错误,导致不能被解释器解释或不能被编译器编译);
逻辑错误(由于不完整或不合法的输入所致,也可能是逻辑无法生成,计算或输出结果需要的过程无法执行等);
python异常是一个对象,表示错误或意外情况,在python检测到一个错误时,将触发一个异常;
python可以通过异常传导机制传递一个异常对象,发出一个异常情况出现的信号,程序员也可在代码中手动触发异常;
python异常也可理解为,程序出现了错误而在正常控制流以外采取的行为;
第一阶段(解释器触发异常,此时当前程序流将被打断),第二阶段(异常处理,如忽略非致命性错误,减轻错误带来的影响等);
程序运行时若有异常要能够捕获到,不能任由异常来中断程序的运行;
在try-except中,使用except:可捕获所有异常,不建议这么做,(1)当用户试图ctrl+c时也会捕获并出现自定义提示信息,使程序无法关闭,(2)不利于程序员排错;
try段中的某一条语句出现异常剩下的语句将不会执行;
异常的功用:
错误处理(python的默认处理:停止程序,打印错误消息,使用try语句处理异常并从异常中恢复);
事件通知(用于发出有效状态信号);
特殊情况处理(无法调整代码去处理的场景);
终止行为(try/finally语句可确保执行必须的结束处理机制);
非常规控制流程(异常是一种高级跳转goto机制);
检测和处理异常:
异常通过try语句来检测,任何在try语句块里的代码都会被检测,以检查有无异常发生;
try语句主要有两种形式:
try-except(检测和处理异常,可以有多个except,支持使用else子句处理,没有探测异常的执行的代码),try-except语法:
try:
try_suite
except Exception[,reason]:
except_suite
注:定义了进行异常监控的一段代码,并且提供了处理异常的机制
注:没有符合的except分句时,异常会向上传递到程序中的之前进入try中或到进程的顶层(解释器)
try-except-else语法:
try:
try_suite
except Exception1[,reason]:
suite_exception1
except (Exception2[,Exception3,...])[,reason]: #(一次捕获多个异常,要定义为元组形式)
suite_exception
except: #(except后不跟任何异常状态,此句则是捕获一切异常)
suite_except
else:
else_suite
注:except分句个数无限制,但else只能有一个,只有在没有异常发生时else分句才执行
try-finally(仅检查异常,并做一些必要的清理工作,仅能有一个finally),语法:
try:
try_suite
finally:
finally_suite
注:无论异常是否发生,finally子句都会执行,finally只进行了清理并没处理异常,常用于定义必须进行的清理动作,如关闭文件、断开服务器连接等,finally中的所有代码执行完毕后会继续向上一层引发异常
try-except-finally(try语句的复合形式),语法:
try:
try_suite
except Exception1:
suite_exception1
except (Exception2,Exception3):
suite_exception
……
else:
else_suite
finally:
finally_suite
注:可在try-finally语句中嵌套try-except语句
try:
try:
try_suite
except Exception1:
suite_exception1
except (Exception2,Exception3):
suite_exception
else:
else_suite
finally:
finally_suite
举例1:
In [3]: try:
...: f1=open('/tmp/a.txt') #(打开的这个文件不存在,会引发异常)
...: except IOError,e: #(将原因保存在e这个变量中)
...: print 'could not openfile',e
...:
could not open file [Errno 2] No such fileor directory: '/tmp/a.txt'
举例2:
In [5]: try:
...: f1=open('/tmp/python2.7/lib/pkg1/test.py','r')
...: f1.write('hello world') #(以读方式打开存在的文件往里写会引发异常)
...: finally: #(关闭文件后继续向上触发异常)
...: f1.close()
...:
---------------------------------------------------------------------------
IOError Traceback(most recent call last)
<ipython-input-5-dcdc4ac7f7ac> in<module>()
1 try:
2 f1=open('/tmp/python2.7/lib/pkg1/test.py','r')
----> 3 f1.write('hello world')
4 finally:
5 f1.close()
IOError: File not open for writing
举例3:
[root@localhost ~]# vim try_except.py
---------------------script start--------------------
#!/usr/bin/python2.7
#filename:try_except.py
try:
while True:
d1=raw_input('input aninteger:')
if d1=='quit':break
d2=raw_input('input another aninteger:')
print int(d1)/int(d2)
except ZeroDivisionError,e:
print 'not 0',e
except ValueError:
print 'not string'
except:
print 'unknown error'
-----------------script end-----------------------
[root@localhost ~]# chmod 755 try_except.py
[root@localhost ~]# ./try_except.py
input an integer:file
input another an integer:2
not string
[root@localhost ~]# ./try_except.py
input an integer:3
input another an integer:0
not 0 integer division or modulo by zero
[root@localhost ~]# ./try_except.py
input an integer:5
input another an integer:1
5
raise自定义异常:
raise语句可显式的触发异常,语法:
raise [SomeException[,args[,traceback]]]
注:
SomeException可选,异常的名字,仅能使用字符串、类或实例;
args可选,以元组的形式传递给异常的参数;
traceback可选,异常触发时新生成的一个用于异常--正常化的跟踪记录,多用于重新触发异常时;
raise语句的用法:
raise exclass(触发一个异常,从exclass生成一个实例(不含任何异常参数));
raise exclass()(同上,但现在不是类,通过函数调用作用于类名生成一个新的exclass实例,同样也没有异常参数);
raise exclass,args(同上,但同时提供异常参数,可以是一个参数也可以是tuple);
raise exclass(args)(同上)
raise exclass,args,tb(同上,但提供一个跟踪记录traceback对象tb供使用);
raise exclass,instance(通过实例触发异常,通常是exclass的实例;如果实例是exclass的子类实例,那这个新异常的类型会是子类的类型而不是exclass;如果实例既不是exclass的实例也不是exclass子类的实例,那么会复制此实例为异常参数去生成一个新的exclass实例);
raise instance(通过实例触发异常,异常类型是实例的类型,等价于raise instance.__class__);
raise string(触发字符串异常,忽略,已过时);
raise string,args(同上,但触发伴随着args);
raise string,args,tb(同上,但提供了一个traceback跟踪记录对象tb供使用);
raise(1.5版本新增,重新触发前一个异常,如果之前没有异常触发TypeError);
举例:
In [1]: def crossProduct(seq1,seq2):
...: if not seq1 or not seq2: #(此句not seq1判断是空则执行此段代码,若要判断是否是序列用type(seq1)!='list')
...: raise ValueError,'sequence arguments must be non-empty'
...: return [(x1,x2) for x1 in seq1 for x2 inseq2]
...:
In [2]: l1=[]
In [3]: l2=[]
In [4]: crossProduct(l1,l2)
---------------------------------------------------------------------------
ValueError Traceback (mostrecent call last)
<ipython-input-4-be2e6a01d611> in<module>()
----> 1 crossProduct(l1,l2)
<ipython-input-1-42af91fe77d4> incrossProduct(seq1, seq2)
1 def crossProduct(seq1,seq2):
2 if not seq1 or not seq2:
----> 3 raise ValueError,'sequence argumentsmust be non-empty'
4 return [(x1,x2) for x1 inseq1 for x2 in seq2]
5
ValueError: sequencearguments must be non-empty
In [5]: l3=[1,2,3]
In [6]: l4=[4,5,6]
In [7]: crossProduct(l3,l4)
Out[7]: [(1, 4), (1, 5), (1, 6), (2, 4),(2, 5), (2, 6), (3, 4), (3, 5), (3, 6)]
python异常是内置的经典类Exception的子类的实例,为了向后兼容,python还允许使用字符串或任何经典类实例;
python2.5之后Exception是从BaseException继承的新式类,python自身引发的所有异常都是Exception的子类的实例,大多数标准异常都由StandardError派生的,其中有三个抽象的子类:
ArithmeticError(由于算术错误而引发的异常基类,OverflowError、ZeroDivisionError、FloatingPointError);
LookupError(容器在接收到一个无效键或索引时引发的异常的基类,IndexError、KeyError);
EnvironmentError(由于外部原因而导致的异常的基类,IOError、OSError、WindowError);
标准异常类:
AssertionError(断言语句失败);
AttributeError(属性引用或赋值失效);
FloatingPointError(浮点型运算失败);
IOError(I/O操作失败);
ImportError(import语句不能找到要导入的模块,或不能找到该模块特别请求的名称);
IndentationError(解析器遇到了一个由于错误的缩进而引发语法错误);
IndexError(用来索引序列的整数超出了范围);
KeyError(用来索引映射的键不在映射中);
KeyboardInterrupt(用户按了中断键ctrl+c、ctrl+break|delete);
MemoryError(运算耗尽内存);
NameError(引用了一个不存在的变量名);
NotImplementedError(由抽象基类引发的异常,用于指示一个具体的子类必须覆盖一个方法);
OSError(由模块os中的函数引发的异常,用来指示平台相关的错误);
OverflowError(整数运算的结果太大导致溢出);
SyntaxError(语法错误);
SystemError(python本身或某些扩展模块中的内部错误);
TypeError(对某对象执行了不支持的操作);
UnboundLocalError(引用未绑定的本地变量);
UnicodeError(在Unicode字符串之间进行转换时发生的错误);
ValueError(应用于某个对象的操作或函数,这个对象具有正确的类型,但有不适当的值);
WindowsError(模块os中的函数引发的异常,与windows平台相关);
ZeroDivisionError(除数为0错误);
自定义异常类:
自定义异常和多重继承,较有效的方法是从自定义异常类和标准异常类进行多重继承,如:
class CustomAttributeError(CustomException,AttributeError):
pass
标准库中使用的其它异常,python标准库中的许多模块都定义了自己的异常类,如socket中的socket.error,等同于自定义的异常类;
assert语句:
简化版的自定义异常方式,手动触发异常,用在程序中调试代码,语法:
assert condition[,expression]
如果condition条件满足,则assert不做任何操作;如果condition条件不满足,则assert使用expression作为参数实例化AssertionError并引发结果实例;
如果运行python时使用了-O优化选项,则assert将是一个空操作,编译器不为assert语句生成代码,运行python时不使用-O选项,则__debug__内置变量为True,否则为False;
assert语句相当于:
if __debug__:
ifnot condition:
raiseAssertionError,<expression>
例如:assert 1==0,'something wrong'
python执行环境:
python解释器启动:
python [options] [-c cmd|filename|-] [args]
options有:
-h(打印所有可用命令行选项);
-i(interactive在程序或脚本执行后进入交互模式);
-O(optimize优化模式);
-oo(优化模式,在创建.pyo文件时删除文档字符串);
-v(verbose详细模式,跟踪导入语句);
-V(version打印版本号并退出);
-c cmd(以字符串形式执行command);
-3(启用将从python3中删除或更改某些功能的警告);
-B(阻止导入时创建.pyc或.pyo文件);
-E(忽略环境变量);
-m module(以脚本的形式运行库module);
-Qarg(指定python2中除法运算符的行为,值为-Qold(默认值),-Qnew,-Qwarn,-Qwarnall);
-s(阻止将用户站点目录添加到sys.path);
-S(阻止包含site初始化模块);
-t(报告关于不一致的标准使用警告);
-tt(由于不一致的标签使用而导致TabError异常);
-u(未缓冲的二进制stdout和stdin);
-U(Unicode字面量,所有字符串字面量都以Unicode形式处理(仅在python2中使用));
-x(跳过源程序的第一行);
例如:
#python -c 'print "hello"'
#python script.py -i(执行完脚本进入交互模式)
python解释器环境变量:
PYTHONPATH(以冒号分隔的模块搜索路径);
PYTHONHOME(python安装的位置);
PYTHONOPTIMIZE(相当于-O);
PYTHONSTARTUP(以交互方式启动时执行的文件);
PYTHONINSPECT(相当于-i);
PYTHONUNBUFFERED(相当于-u);
PYTHONIOENCODING(针对stdin、stdout、stderr的编程和错误处理,这是一个encoding[:errors]形式的字符串,如utf-8或utf-8:ignore);
PYTHONDONTWRITEBYTE(相当于-B);
PYTHONNOUSERSITE(相当于-s);
PYTHONVERBOSE(相当于-v);
PYTHONUSERBASE(每个用户站点包的根目录);
PYTHONCASEOK(指示为导入所使用的模块名称,使用不区分大小写的匹配方式);
python代码的测试、调试与探查:
python文档字符串(如果函数、类、模块的第一行是一个字符串,这个字符串就称为docstrings文档字符串,内置函数help()或对象的默认方法__doc__可显示这些文档字符串);
doctest模块:
允许在文档字符串内嵌入注释以显示各种语句的期望行为。尤其是函数和方法的结果;
此处的文档字符串看起来如同一个交互式shell会话,可用于测试文档是否与程序主体保持同步,或基于文档对程序本身做测试;若文档字符串中的结果与预期结果不一致,测试会显示出错的结果信息;
创建可测试的模块(在模块的尾部添加if __name__=='__main__':,若模块在解释器中直接运行#pythontest.py即能进行自我测试);
举例1:
In [1]: def sum(num1,num2):
...: '''The summary of num1and num2.
...: >>> sum(2,5)
...: 7
...: >>> sum(3,4)
...: 7
...: '''
...: return num1+num2
...:
In [2]: help(sum)
Help on function sum in module __main__:
sum(num1, num2)
The summary of num1 and num2.
>>> sum(2,5)
7
>>> sum(3,4)
7
(END)
In [3]: sum.__doc__
Out[3]: 'The summary of num1 andnum2.\n >>>sum(2,5)\n 7\n >>>sum(3,4)\n 7\n
举例2:
[root@localhost ~]# vim test_module.py
------------------------script start-----------------------
#!/usr/bin/python2.7
#filename:test_module.py
def add(num1,num2):
'''
>>> add(8,8) #(注意此处>>>后要跟一个空格)
16
'''
return num1+num2
if __name__=='__main__':
print 'i am running,no import'
-----------------------script end-------------------------------
[root@localhost ~]# chmod 755test_module.py
[root@localhost ~]# ./test_module.py
i am running,no import
[root@localhost ~]# ipython
……
In [1]: import doctest,test_module
In [2]: doctest.testmod(test_module)
Out[2]: TestResults(failed=0, attempted=1)
In [3]: doctest.testmod(test_module,verbose=True)
Trying:
add(8,8)
Expecting:
16
ok
1 items had no tests:
test_module
1 items passed all tests:
1tests in test_module.add
1 tests in 2 items.
1 passed and 0 failed.
Test passed.
Out[3]: TestResults(failed=0, attempted=1)
总结else语句:
与if搭配(要么怎样,要么不怎样);
与循环while、for搭配(干完了能怎样,干不完就别想怎样);
与try-except-else-finally搭配(没有问题,那就干吧);
举例:
In [12]: try:
int('abc')
except ValueError as reason:
print 'has a problem',reason
else:
print "IT's ok"
....:
has a problem invalidliteral for int() with base 10: 'abc'
In [13]: try:
int(55)
except ValueError as reason:
print 'has a problem',reason
else:
print "IT's ok"
....:
IT's ok
简洁的with语句:
可自动的将打开的文件在不用时关闭(类似于try-finally中,finally段中的语句做的是收尾工作);
以下两个例子效果相同,使用with语句更简洁;
在try-except中,使用except:可捕获所有异常,不建议这么做,(1)当用户试图ctrl+c时也会捕获并出现自定义提示信息,使程序无法关闭,(2)不利于程序员排错;
try段中的某一条语句出现异常剩下的语句将不会执行;
举例1:
In [15]: try:
....: f=open('/tmp/test1.txt','r+')
....: for each in f:
....: print each,
....: except OSError as reason:
....: print 'has problem',reason
....: finally:
....: f.close()
....:
11111
22222
3333
4444
5555
举例2:
In [16]: try:
....: withopen('/tmp/test1.txt','r+') as f:
....: for each in f:
....: print each,
....: except OSError,reason:
....: print 'has problem',reason
....:
11111
22222
3333
4444
5555
python不仅自己带着电池Batteries included(python标准库,包含一般任务所需要的模块),还带着充电器;
python设计哲学:优雅、明确、简单;用一种方法,最好是只有一种方法来做一件事;使用现成的模块
https://pypi,python.org/pypi
PEP,python enhancementproposals,python增强建议书,用来规范与定义python的各种加强与延伸功能的技术规格,好让python开发社区能有共同遵循的依据,每个PEP都有一个唯一的编号,一旦给定就不再改变,如PEP3000是用来定义python3.0的相关技术规格,PEP333是python的web应用程序界面WSGI(web server gateway interface1.0)的规范,关于PEP本身的相关规范定义在PEP1,而PEP8定义了python代码的风格指南;
PEP0(https://www.python.org/dev/peps/)
In [5]: import timeit
In [6]: help(timeit) #(Tool for measuringexecution time of small code snippets.)
In [7]: timeit.__doc_ #(显示的信息一团乱麻)
Out[7]: "Tool for measuring executiontime of small code snippets.\n\nThis module avoids a number of common traps formeasuring execution\ntimes. See also TimPeters' introduction to the Algorithms chapter in\nthe Python Cookbook,published by O'Reilly.\n\nLibrary usage: see the Timer class.\n\nComma……
In [8]: dir(timeit) #(查看支持的属性和方法)
Out[8]:
['Timer',
'__all__',
'__builtins__',
'__doc__',
'__file__',
'__name__',
'__package__',
'_template_func',
'default_number',
'default_repeat',
'default_timer',
'dummy_src_name',
'gc',
'itertools',
'main',
'reindent',
'repeat',
'sys',
'template',
'time',
'timeit']
In [9]: timeit.__all__ #(并非所有模块都有__all__这一属性,__all__中放的是过滤出的作者希望能被外部调用的方法,开发时尽量把可供外部调用的方法放在__all__中)
Out[9]: ['Timer']
In [10]: timeit.__file__ #(指明源代码位置)
Out[10]:'/usr/local/python2.7/lib/python2.7/timeit.pyc'
转载于:https://blog.51cto.com/jowin/1790512