可升级:Python提倡简洁的代码设计、高级的数据结构和模块化的组件,确保灵活性、
扩展性:兼容扩展c和java
易读写,易维护
健壮性:Python提供了“安全合理”的退出机制,Python由于错误崩溃,解释程序就会转出一个“堆栈跟踪”,那里面有可用到的全部信息,包括你程序崩溃的原因以及是那段代码(文件名、行数、行数调用等等)出错了。这些错误被称为异常。如果在运行时发生这样的错误,Python能够监控这些错误并进行处理。描述错误的类型和位置,还能指出代码所在模块。
快速原型开发工具:Python标准库是很完备的,如果你在其中找不到所需,那么第三方模块或包就会为你完成工作提供可能。
内存管理是由Python解释器负责。C或者C++最大的弊病在于内存管理是由开发者负责的,会分散精力
类似于Java,Python是字节编译的,可以生成一种近似机器语言的中间形式,提升性能。
Unix中,可执行文件通常会将Python安装到/usr/local/bin子目录下,而库文件则通常安装在/usr/local/lib/python2.x子目录下
运行Python
命令行和脚本模式(解释器执行)
命令行选项:
-d提供调试输出
-O生成优化的字节码(生成.pyo文件)
-S不导入site模块以在启动时查找Python路径
-v冗余输出(导入语句详细追踪)
-mmod将一个模块以脚本形式运行
-Qopt除法选项(参阅文档)
-ccmd运行以命令行字符串形式提交的Python脚本
file从给定的文件运行Python脚本(参阅后文)
脚本头部添加“#!/usr/local/bin/python”正确的安装位置,可以找到python,否则给出错误提示。或者借用unix下env环境变量设置
#!/usr/bin/envpython
设置好后,不用显式的调用Python解释器,直接输入脚本名,脚本首行书写的启动指令会自动执行。
Eclipse,pycharm,idle等等,自己搜下.
表示最后一个表达式的值。所以上面的代码执行之后,下划线变量会包含字符串:
Python用下划线作为变量前缀和后缀指定特殊变量
_xxx保护变量不能用’frommoduleimport*’导入
__xxx__系统定义名字的专用方法
__xxx类中的私有变量名
程序员避免用下划线作为变量名的开始。
“单下划线”开头的成员变量叫做保护变量,是只有类对象和子类对象自己能访问到这些变量。这种变量不能直接访问,需通过类提供的接口进行访问,不能用“fromxxximport*”而导入。
只以“双下划线”开头的是私有成员,意思是只有类对象自己能访问,连子类对象也不能访问到这个数据。
以双下划线开头和结尾的如__foo__,是特殊方法标识,如__init__()代表类的构造函数。
可实现字符串替换功能,类似C语言:
>>>print"%sisnumber%d!"%("Python",1)
Pythonisnumber1!
符号>>用来重定向输出,将输出重定向到标准错误输出:
importsys
print>>sys.stderr,'Fatalerror:invalidinput!'
将输出重定向到日志文件的例子:
logfile=open('/tmp/mylog.txt','a')
print>>logfile,'Fatalerror:invalidinput!'
logfile.close()
内建函数help()得到一个生疏函数的帮助,用函数名得到相应的帮助信息
>>>help(raw_input)
Helponbuilt-infunctionraw_inputinmodule__builtin__:
raw_input(...)
raw_input([prompt])->string
注意,文档字符串的特别注释,是运行时访问,用来自动生成文档,如deffoo():
"Thisisadocstring."
returnTrue
函数名下一行,如果内容多,用三个单引号“’”,就可以跨行了
+-*///%**
两种除法运算符,单斜杠用作传统除法,双斜杠用作浮点除法(对结果进行四舍五入)
双星号(**)为乘方运算符,如3**2结果为9
<<=>>===!=<>
不许类型关键字,直接复制
>>>miles=1000.0
>>>name='Bob'
>>>counter=counter+1
支持增量赋值
n=n*10
n*=10
不支持自增1和自减1运算符,--n解释为-(-n)从而得到n,同样++n的结果也是n.
int(有符号整数)
long(长整数):长整数后缀“L”如2001L
bool(布尔值)
float(浮点值)
complex(复数)
Python的长整数所能表达的范围远远超过C语言的长整数,事实上,Python长整数仅受限于用户计算机的虚拟内存总数。如果你熟悉Java,Python的长整数类似于Java中的BigInteger类型。
True会被当成整数值1,而False则会被当成整数值0
复数(包括-1的平方根,即所谓的虚数)在其它语言中通常不被直接支持(一般通过类来实现)。
decimal用于十进制浮点数。不是内建类型,需要导入decimal模块,使用如字1.1无法用二进制浮点数精确表示
>>>1.1
1.1000000000000001
>>>printdecimal.Decimal('1.1')
1.1
可以看成是只读的列表。通过切片运算([]和[:])可以得到子集,这一点与字符串的使用方法一样。但切片得到的结果也是元组(不能被修改)
>>>aTuple=('robots',77,93,'try')
>>>aTuple
('robots',77,93,'try')
>>>aTuple[:3]
('robots',77,93)
>>>aTuple[1]=5
Traceback(innermostlast):
File"
TypeError:objectdoesn'tsupportitemassignment
接受可迭代对象(例如序列或迭代器)作为其参数,每次迭代其中一个元素。如
foritemin['e-mail','net-surfing','homework','chat']:
printitem
Python提供了一个range()内建函数来生成这种列表,满足for的需要,接受一个数值范围,生成一个列表:
>>>foreachNuminrange(3):
printeachNum
也可以用len()配合foriinrange(len(foo))
同时循环两个,enumerate()同时循环索引和元素
fori,chinenumerate(foo):
printch,'(%d)'%i
在一行中使用一个for循环将所有值放到一个列表当中
>>>squared=[x**2forxinrange(4)]
>>>foriinsquared:
printi
输出结果:
0
1
4
9
更复杂如挑选出符合要求的值放入列表
sqdEvens=[x**2forxinrange(8)ifnotx%2]
foriinsqdEvens:
输出结果
16
36
注意,file()内建函数,功能等同于open(),这个名字可以更确切的表明它是一个工厂函数
可以是简单的数据值,也可以是可执行对象,如函数和方法。
使用“.”访问对象属性,如object.attribute。
代码
filename=raw_input('Enterfilename:')
fobj=open(filename,'r')
foreachLineinfobj:
printeachLine,
fobj.close()
其中,使用逗号来抑制自动生成的换行符号。文件中的每行文本已经自带了换行字符,如果我们不抑制print语句产生的换行符号,文本在显示时就会有额外的空行产生。
但对于很大的文件来说,上面的代码会占用太多的内存,这时你最好一次读一行。
遇到错误抛出的信息,迅速定位问题并进行调试
代码添加错误检测及异常处理,封装在try-except语句当中。except之后是处理错误的代码。可以用raise直接抛出一个异常。
try:
printeachLine,fobj.close()
exceptIOError,e:
print'fileopenerror:',e
class关键字定义,提供一个可选的父类或者说基类;如果没有合适的基类,
那就使用object作为基类。class行之后是可选的文档字符串,静态成员定义,及方法定
义。
classFooClass(object):
"""myveryfirstclass:FooClass"""
version=0.1#class(data)attribute
def__init__(self,nm='JohnDoe'):
"""constructor"""
self.name=nm#classinstance(data)attribute
print'Createdaclassinstancefor',nm
defshowname(self):
"""displayinstanceattributeandclassname"""
print'Yournameis',self.name
print'Mynameis',self.__class__.__name__
defshowver(self):
"""displayclass(static)attribute"""
printself.version#referencesFooClass.version
defaddMe2Me(self,x):#doesnotuse'self'
"""apply+operationtoargument"""
returnx+x
其中定义了一个静态变量version,它将被所有实例及四个方法共享,__init__(),showname(),showver(),及熟悉的addMe2Me().这些show*()方法并没有做什么有用的事情,仅仅输出对应的信息。
__init__()方法,名字开始和结束都有两个下划线的方法都是特殊方法。这个方法用于类实例初始化时首先调用,类似构建函数。不过不象其它语言中的构建函数,它并不创建实例--它仅仅是你的对象创建后执行的第一个方法。它的目的是执行一些该对象的必要的初始化工作。默认的__init__()方法什么都不做,可以覆盖重写。
每个方法都有的一个参数,self.是类实例自身的引用。类似其他语言使用的this
PEP就是一个Python增强提案(PythonEnhancementProposal),这也是在新版Python中增加新特性的方式。不但提供了新特性的完整描述,还有添加这些新特性的理由,如果需要的话,还会提供新的语法、技术实现细节、向后兼容信息等等。
20、实用的内建函数
dir([obj])显示对象的属性,如果没有提供参数,则显示全局变量的名字
type(obj)返回对象的类型(返回值本身是一个type对象!)
int()
str()
help()
代码跨行写用反斜线(\),继续上一行
而分号(;)将两个语句连接在一行中
使用四个空格宽度,避免使用制表符
赋值并不是直接将一个值赋给一个变量,尽管其它语言编程如此。但Python中,对象是通过引用传递的。在赋值时,不管这个对象是新创建的,还是一个已经存在的,都是将该对象的引用(并不是值)赋值给变量。
c语言中,赋值语句其实是被当成一个表达式(可以返回值),但python中不行,Python的赋值语句不会返回值,非法语句如
>>>x=1
>>>y=(x=x+1)#assignmentsnotexpressions!File"
报错
y=(x=x+1)
^
SyntaxError:invalidsyntax
Python不支持类似x++或--x这样的前置/后置自增/自减运算
但支持增量赋值,运算符如下
+=-=*=/=%=**=
<<=>>=&=^=|=
多个变量同时赋值,如x,y,z=1,2,'astring'
交换两个变量值想x和y
x,y=1,2
x,y=y,x
关键字
专用下划线标识符
_xxx不用'frommoduleimport*'导入
__xxx__系统定义名字
避免用下划线作为变量名的开始,下划线对解释器有特殊的意义。
变量名_xxx被看作是“私有的”,在模块或类外不可以使用。当变量是私有的时候,用_xxx来表示变量是很好的习惯。因为变量名__xxx__对Python来说有特殊含义。
模块结构和布局,推荐的标准风格,如下
使用main()函数,检查__name__变量的值
如果模块是被导入,__name__的值为模块名字
如果模块是被直接执行,__name__的值为'__main__'
变量无须指定类型
程序员不用关心内存管理
变量名会被“回收”
del语句能够直接释放资源
(1)动态类型
Python语言中,对象的类型和内存占用都是运行时确定的。尽管代码被编译成字节码,Python仍然是一种解释型语言。在创建事,也就是赋值时,解释器会根据语法和右侧的操作数来决定新对象的类型。
(2)内存分配
Python解释器承担了内存管理的复杂任务,底层的事情放心交给Python解释器
Python创建对象,是作为引用来使用(赋值的),创建时在申请一个内存空间,同时为这个内存空间生成一个引用计数器,来记录该对象的引用传递给了多少对象(也是,多少新对象指向它)。所以,x=2,在python中先生成一个值为2的内存空间,并生成对应的引用计数器值为0,再将其的引用传给对象x,内存空间2的引用计数器加1(为1),x=y时,y同样指向内存空间2,其计数器继续加1(为0)。
书上说:Python内部记录着所有使用中的对象各有多少引用。一个内部跟踪变量,称为一个引用计数器。当对象被创建时,就创建了一个引用计数,当不再需要时,引用计数变为0时,它被垃圾回收。
引用计数器增加情况
(1)对象被创建
x=3.14
(2)或另外的别名被创建
y=x
(3)或被作为参数传递给函数(新的本地引用)
foobar(x)
(4)成为容器对象的一个元素
myList=[123,x,'xyz']
引用计数器减少情况
(1)一个本地引用离开了其作用范围。如传入函数的fun(x),x在fun()结束后销毁,对应减1
(2)对象的别名被显式的销毁。
dely#ordelx
(3)对象的一个别名被赋值给其它的对象
x=123
(4)对象被从一个窗口对象中移除
myList.remove(x)
(5)窗口对象本身被销毁
delmyList#orgoesout-of-scope
31、垃圾收集
不再被使用的内存会被一种称为垃圾收集的机制释放。虽然解释器跟踪对象的引用计数,但垃圾收集器负责释放内存。垃圾收集器是一块独立代码,用来寻找引用计数为0的对象。虽然引用计数大于0但也应该被销毁的对象。特定情形会导致循环引用。解释器会暂停下来,试图清理所有未引用的循环。
32、使用局部变量替换模块变量
os.linesep字符串给出当前平台使用的行终止符。为os.linesep属性取了一个新别名,这样做一方面可以缩短变量名,另一方面也能改善访问该变量的性能。
Importos
ls=os.linesep
#writelinestofilewithproperline-ending
fobj=open(fname,'w')
fobj.writelines(['%s%s'%(x,ls)forxinall])
类似os.linesep这样的名字需要解释器做两次查询,模块内部函数需要解释器做两次查询,因为模块也是全局变量。这样做多耗费资源。
一个函数中类似这样频繁使用一个属性,我们建议你为该属性取一个本地变量别名。在查找全局变量之前,总是先查找本地变量,经常用到的模块属性替换为一个本地引用。
33、一种新的Python结构,try-except-else语句
try子句是监测错误的代码块,
1#!/usr/bin/envPython
2#getfilename
3fname=raw_input('Enterfilename:')
4try:
5fobj=open(fname,'r')
6exceptIOError,e:
7print"***fileopenerror:",e
8else:
9#displaycontentstothescreen
10foreachLineinfobj:
11printeachLine,
12fobj.close()
34、必须工具
Python代码风格指南(PEP8),Python快速参考和Python常见问答。
优秀的Python程序员必用一些模块:
Debugger:pdb
Logger:logging
Profilers:profile,hotshot,cProfile
调试模块pdb允许你设置(条件)断点,代码逐行执行,检查堆栈。它还支持事后调试。
logging模块是在Python2.3中新增的,它定义了一些函数和类帮助你的程序实现灵活的日志系统。共有五级日志级别:紧急,错误,警告,信息和调试。
性能测试模块
(1)pyhonprofile模块(Python写成的,最老,最慢)
(2)hotshot模块(C语言写成,性能高)
python2.2中新增,目标是取代profile模块,修复profile模块的一些错误。
(3)hotshot模块
(4)cProfile模块(C语言)
身份:每个对象唯一的身份标识,使用内建函数id()来得到,可以认为是对象的内存地址。不用关心。
类型:内建函数type()查看对象类型,返回值为对象非字符串。类型决定值、操作、规则,如
type(type(42))
值:对象数据项
特殊类型NoneType:只有一个值None,没有任何运算,没有任何内建方法。布尔值总是False。
(1)代码:编译的代码片段,可执行对象。通过调用内建函数compile()可以得到代码对象。被exec命令或eval()内建函数来执行
(2)帧:执行栈帧,命令执行时的记录对象,包含Python解释器在运行时所需要知道的所有信息
(3)跟踪记录:报异常时创建追踪对象,保存栈追踪信息。当异常有自己的处理程序,则去访问这个跟踪记录的对象,执行处理异常。
(4)切片对象:Python扩展的切片语法。sequence[start1:end1,start2:end2].也可以由内建函数slice()来生成.不同的索引切片操作,包括
步进切片:sequence[起始索引:结束索引:步进值],例子
>>>foolist=[123,'xba',342.23,'abc']
>>>foolist[::-1]
['abc',342.23,'xba',123]
多维切片:语法sequence[start1:end1,start2:end2],
省略切片:sequence[...,start1:end1]
(5)省略:用于扩展切片语法中,起记号作用。唯一的名字Ellipsis,布尔值始终为True.
(6)Xrange:返回一个对象
(1)对象值的比较:可以连着
3<4<7#sameas(3<4)and(4<7)
4<3<5!=2<7
不等于使用“!=”
对象间用is/isnot比较,如
b=2.5e-5
a=b
aisb
返回结果为TRUE
(2)特殊的对象:
简单整数对象被缓存,多次赋值只用这一个对象。
整数对象和字符串对象是不可变对象,所以Python会高效的缓存,造成我们认为Python应该创建新对象时,却没有创建新对象的假象。例子如下
>>>a=1
>>>id(a)
8402824
>>>b=1
>>>id(b)
>>>
>>>c=1.0
>>>id(c)
8651220
>>>d=1.0
>>>id(d)
8651204
其中,a和b指向了相同的整数对象(地址一样),但是c和d并没有指向相同的浮点数对象(地址不同)。也就是说,Python仅缓存简单整数(但这个功能不要使用),目前,简单整数的缓存范围是(-1,100),不过这个范围是会改变的,所以请不要在你的应用程序使用这个特性。
另外,预定义缓存字符串表之外的字符串,不再有任何引用指向它,那这个字符串将不会被缓存。对象回收器一样可以回收不再被使用的字符串
cmp(obj1,obj2)比较obj1和obj2,根据比较结果返回整数i:
i<0ifobj1 i>0ifobj1>obj2 i==0ifobj1==obj2 repr(obj)或`obj`返回一个对象的字符串表示 str(obj)返回对象适合可读性好的字符串表示 type(obj)得到一个对象的类型,并返回相应的type对象 注意repr()或反引号运算符“``”,以及str()三者完全一样,repr()输出对Python比较友好,而str()的输出对人比较友好。 repr()和``做的是完全一样的事情,返回一个对象的“官方”字符串表示,也就是说绝大多数情况下可以通过求值运算(使用eval()内建函数)重新得到该对象,但str()则有所不同。生成一个对象的可读性好的字符串表示,返回结果通常无法用于eval()求值,但用于print语句输出。 比type()好一点,功能一样。因为提升性能方法: (1)减少函数调用次数(尽量使用变量做比较项目) (2)减少查询次数,from-import,你可以减少一次查询: fromtypesimportIntType iftype(num)isIntType... Python2.2统一了类型和类,所有内建类型也都是类。其内建转换函数如int(),type(),list()等等,都是类。看着像函数,实际是类。调用时也是生成实例。 “基本”,是指这些类型都是Python提供的标准或核心类型。 “内建”,是由于这些类型是Python默认就提供的 “数据”,因为他们用于一般数据存储 “对象”,因为对象是数据和功能的默认抽象 “原始”,因为这些类型提供的是最底层的粒度数据存储 “类型”,因为他们就是数据类型 标量/原子类型数值(所有的数值类型),字符串(全部是文字) 容器类型列表、元组、字典 可变类型列表,字典 不可变类型数字、字符串、元组 1,char或byte 如果要使用类似功能,可用长度为1的字符串,作为代替表示字符或8比特整数。 2,指针 内存地址python自动管理,不能手动管理,最多用id()函数得到对象身份号,类似但不是地址。Python中,一切都是指针。 3,整型不分int,short,long Python的标准整型,融合了C中的长整型功能。而python的长整型(后边加L)是具有超级取值空间。如果两个很大的数相乘,Python会自动的返回一个长整数给你而不会报错。不像C。 4,Python决定不支持单精度浮点数 Python中只有一种浮点数类型。但是对需要更高精确度而宁愿放弃更大的取值范围情况,Python还有一种十进制浮点数类型Decimal,使用时需要decimal模块 Python标准整数类型等价于C中(有符号)长整型。八进制整数以数字“0”开始,十六进制整数则以“0x”或“0X”开始 整数值后面加个L(大写或小写都可以)。十进制,八进制,或十六进制都行。 C的长整型取值范围32位或64位。而python长整数不同,没有位数限制,能表达的值仅仅与机器的(虚拟)内存大小有关,范围很大,可以表达超级整数。 注意: python中,整型计算多大会自动转换成长整型,所以 python不存在整数超范围的错误,只会给个warning,如 2<<32 给出信息:__main__:1:FutureWarning:x< 。每个浮点数占8个字节(64比特),完全遵守IEEE754号规范(52M/11E/1S),其中52个比特用于表示底,11个比特用于表示指数(可表示的范围大约是正负10的308.25次方),剩下的一个比特表示符号。但实际精度依赖于机器架构和创建Python解释器的编译器。 “+”对不用类型不同操作,不仅是加法 整数转换为浮点数,非复数转换为复数。Python提供了coerce()内建函数来帮助你实现这种转换。 1//2#floorsresult,returnsinteger#地板除,返回整数 >>>1.0//2.0#floorsresult,returnsfloat#地板除,返回浮点数 0.0 expr1//expr2表达式1地板除以表达式2 expr1%expr2表达式1对表达式2取 >>>-1//2#moveleftonnumberline#返回比–0.5小的整数,也就是-1 取反(~),按位与(&),或(|)及异或(^)及左移(<<)和右移(>>)只支持整数。 五个数值运算内建函数: abs(num)返回num的绝对值 coerce(num1,num2)将num1和num2转换为同一类型,然后以一个元组的形式返回。 divmod(num1,num2)除法-取余运算的结合。返回一个元组(num1/num2,num1%num2)。对浮点数和复数的商进行下舍入(复数仅取实数部分的商) pow(num1,num2,mod=1)取num1的num2次方,如果提供mod参数,则计算结果再对mod进行取余运算 round(flt,ndig=0)接受一个浮点数flt并对其四舍五入,保存ndig位小数。若不提供ndig参数,则默认小数点后0位。 round()仅用于浮点数。(译者注:整数也可以,不过并没有什么实际意义) 其中,coerce(),返回一个类型转换后的包含两个数值元素的元组。是不依赖Python解释器的数据类型转换函数,如 >>>coerce(1,2) (1,2) >>>coerce(1.3,134L) (1.3,134.0) >>>coerce(1j,134L) (1j,(134+0j)) >>>coerce(1.23-41j,134L) ((1.23-41j),(134+0j)) divmod()内建函数把除法和取余运算结合起来,返回一个包含商和余数的元组 >>>divmod(10,3) (3,1) 函数pow()是指数运算,功能和双星号(**)一样,但pow(x,y,z)有第三个可选的参数,叫余数参数。pow()先进行指数运算,然后将运算结果和第三个参数进行取余运算。这个特性主要用于密码运算,并且比pow(x,y)%z性能更好 (1)进制转换函数oct()和hex() >>>hex(23094823l) '0x1606627L' >>>hex(65535*2) '0x1fffe' >>>oct(255) '0377' >>>oct(23094823l) '0130063047L' >>>oct(65535*2) '0377776' (2)ASCII转换函数ord()和chr() ord('a') 97 >>>ord('A') 65 >>>chr(97) 'a' >>>chr(65L) 'A' 另外,注意 chr(num)将ASCII值的数字转换成ASCII字符,范围只能是0<=num<=255 ord(chr)接受一个ASCII或Unicode字符(长度为1的字符串),返回相应的ASCII或Unicode值 unichr(num)接受Unicode码值,返回其对应的Unicode字符。所接受的码值范围依赖于Python是构建于UCS‐2还是UCS‐4 天生缺憾的表达,如 >>>0.1 0.1000000000000001 这些片断不停的重复直到舍入出错。所以针对数据类型,使用对应的类型 decimal十进制浮点运算类Decimal array高效数值数组(字符,整数,浮点数等等) math/cmath标准C库数学运算函数。常规数学运算在match模块, 复数运算在cmath模块 Operator数字运算符的函数实现。比如tor.sub(m,n)等价于m-n random多种伪随机数生成器 这些片断不停的重复直到舍入出错 高级的数字科学计算应用的著名的第三方包Numeric(NumPy)和SciPy: randint()两个整数参数,返回二者之间的随机整数 randrange()它接受和range()函数一样的参数,随机返回 range([start,]stop[,step])结果的一项 uniform()几乎和randint()一样,不过它返回的是二者之间的一个浮点数(不包括范围上限)。 random()类似uniform()只不过下限恒等于0.0,上限恒等于1.0 choice()随机返回给定序列(关于序列,见第六章)的一个元素 seq[ind]获得下标为ind的元素 seq[ind1:ind2]获得下标从ind1到ind2间的元素集合 seq*expr序列重复expr次 seq1+seq2连接序列seq1和seq2 objinseq判断obj元素是否包含在seq中 objnotinseq判断obj元素是否不包含在seq中 切片有很多小技巧,自己查,如 s[::-1]#可以视作"翻转"操作 s[::2]#隔一个取一个的操作 序列本身内含迭代的概念,是简单的迭代器。 (1)各类型之间的转换:转换实际上是工厂函数,将参数的内容(浅)拷贝到新生成对象 list(iter)把可迭代对象转换为列表 str(obj)把obj对象转换成字符串(对象的字符串表示法) unicode(obj)把对象转换成Unicode字符串(使用默认编码) basestring()抽象工厂函数,其作用仅仅是为str和unicode函数提供父类,所以不能被实例化,也不能被调用 tuple(iter)把一个可迭代对象转换成一个元组对象 其中,建立python后不能更改其身份或类型。建立一个浅拷贝,只拷贝了对象的索引,而不是重新建立了一个对象。 注意,len(),reversed()和sum()函数只能接受序列类型对象作为参数,而剩下的则还可以接受可迭代对象做为参数,另外,max()和min()函数也可以接受一个参数列表,如下 enumerate(iter)接受一个可迭代对象作为参数,返回一个enumerate对象(同时也是一个迭代器),该对象生成由iter每个元素的index值和item值组成的元组(PEP279) len(seq)返回seq的长度 max(iter,key=None)ormax(arg0,arg1...,key=None)返回iter或(arg0,arg1,...)中的最大值,如果指定了key,这个key必须是一个可以传给sort()方法的,用于比较的回调函数 min(iter,key=None)ormin(arg0,arg1....key=None)返回iter里面的最小值;或者返回(arg0,arg2,...)里面的最小值;如果指定了key,这个key必须是一个可以传给sort()方法的,用于比较的回调函数. reversed(seq)接受一个序列作为参数,返回一个以逆序访问的迭代器(PEP322) sorted(iter,func=None,key=None,reverse=False)接受一个可迭代对象作为参数,返回一个有序的列表;可选参数func,key和reverse的含义跟list.sort()内建函数的参数含义一样 sum(seq,init=0)返回seq和可选参数init的总和,其效果等同于reduce(operator.add,seq,init) zip([it0,it1,...itN])返回一个列表,其第一个元素是it0,it1,...这些元素的第一个元素组成的一个元组,第二个...,类推. 特殊的序列:字符串的切片操作 成员操作符(in,notin)判断一个字符或者一个子串(中的字符)是否出现在另一个字符串中。出现则返回True,否则返回False 判断一个字符串是否包含另一个字符串的find()或者index(),还有rfind()和rindex())函数来完成 >>>'bc'in'abcd'True >>>'n'in'abcd'False >>>'nm'notin'abcd'True string模块预定义的字符串: >>importstring >>>string.ascii_uppercase 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' >>>string.ascii_lowercase 'abcdefghijklmnopqrstuvwxyz' >>>string.ascii_letters 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ' >>>string.digits '0123456789' 所以,可以简单的写一个检查小脚本,标识符检查idcheck.py #Python标识符必须以字母或下划线开头,后面跟字母,下划线或者数字 importstring alphas=string.letters+'_' nums=string.digits print'WelcometotheIdentifierCheckerv1.0' print'Testeesmustbeatleast2charslong.' inp=raw_input('Identifiertotest') iflen(myInput)>1: ifmyInput[0]notinalphas: print'''invalid:firstsymbolmustbealphabetic''' else: forotherCharinmyInput[1:]: ifotherCharnotinalphas+nums: print'''invalid:remainingsymbolsmustbealphanumeric''' break print"okayasanidentifier" 性能的的角度,把重复操作作为参数放到循环里面进行是非常低效的,如 whilei print'character%dis:',myString[i] 其中,len(myString)每次都被计算,浪费资源,改成 length=len(myString) whilei %c转换成字符(ASCII码值,或者长度为一的字符串) %r优先用repr()函数进行字符串转换 %s优先用str()函数进行字符串转换 %d/%i转成有符号十进制数 %u转成无符号十进制数 %o转成无符号八进制数 %x/%X(Unsigned)转成无符号十六进制数(x/X代表转换后的十六进制字符的大小写) %e/%E转成科学计数法(e/E控制输出e/E) %f/%F转成浮点数(小数部分自然截断) %g/%G%e和%f/%E和%F的简写 %%输出% 辅助的字符串格式化符号 *定义宽度或者小数点精度 -用做左对齐 +在正数前面显示加号(+) #在八进制数前面显示零('0'),在十六进制前面显示'0x'或者'0X'(取决于用的是'x'还是'X') 0显示的数字前面填充‘0’而不是默认的空格 %'%%'输出一个单一的'%' (var)映射变量(字典参数) m.nm是显示的最小总宽度,n是小数点后的位数(如果可用的话) 举几个例子 >>>"%#X"%108 '0X6C' >>>"%#x"%108 '0x6c' >>>'%.2f'%1234.567890 '1234.57' >>>'%E'%1234.567890 '1.234568E+03' >>>'%e'%1234.567890 '1.234568e+03' >>>'%g'%1234.567890 >>>'%G'%1234.567890 >>>"%e"%(1111111111111111111111L) '1.111111e+21' >>>"%+d"%4 '+4' >>>"%+d"%-4 '-4' 新式的字符串模板 优势是不用记所有细节,而如shell风格那样使用美元符号($).由于新式的字符串Template对象的引进使得string模块又重新活了过来,Template对象有两个方法,substitute()和safe_substitute(),如 >>>fromstringimportTemplate >>>s=Template('Thereare${howmany}${lang}QuotationSymbols') >>>prints.substitute(lang='Python',howmany=3) 结果Thereare3PythonQuotationSymbols >>>s,t='foa','obr' >>>zip(s,t) [('f','o'),('o','b'),('a','r')] str()和unicode()函数都是工厂函数,就是说产生所对应的类型的对象,它们和basestring都可以作为参数传给isinstance()函数来判断一个对象的类型 >>>isinstance(u'\0xAB',str) False >>>notisinstance('foo',unicode) True >>>isinstance(u'',basestring) >>>notisinstance('foo',basestring) 字符串前加u表示编码成Unicode字符串,如,如u’sdfad’是Unicode字符串。 Unicode是编码方式,用于计算机支持都语言的。ASCII编码方式中每个英文字符以七位二进制数的方式存贮在计算机内,其范围是32到126,目前8为可以表示128种。 codec是COder/DECoder的首字母组合,定义了文本跟二进制值的转换方式。ASCII用一个字节把字符转换成数字。而nicode用的是多字节,支持多种编码,常用的四种ASCII,ISO8859-1/Latin-1,UTF-8和UTF-16。 UTF-8编码跟ASCII编码完全相同。用1个到4个字节来表示其他语言的字符,CJK/East这样的东亚文字一般都是用3个字节来表示,那些少用的、特殊的、或者历史遗留的字符用4个字节来表示。Python内部自动完成UTF-8读写工作,不需要关心,免去了直接处理Unicode数据时处理多字节字符的复杂问题。 代码如下: CODEC='utf-8' hello_out=u"Helloworld\n" bytes_out=hello_out.encode(CODEC) hello_in=bytes_in.decode(CODEC) printbytes_out,hello_in UTF-16用16位、两个字节来存储字符,易读写。但顺序需要定义一下,一般UTF-16编码文件都需要一个BOM(ByteOrderMark),或者你显式地定义UTF-16-LE(小端)或者UTF-16-BE(大端)字节序。UTF-16是一种变长编码,不常用,因为不兼容包ASCII,而且一般不会知道或者根本不在意除了基本多文种平面BMP之外到底使用的是那种平面, Python标准库里面的绝大部分模块都是兼容Unicode的。但pickle模块只支持ASCII字符串。如果你把一个Unicode字符串交给pickle模块来unpickle,它会报异常.你必须先把你的字符串转换成ASCII字符串才可以.所以最好是避免基于文本的pickle操作.幸运地是现在二进制格式已经作为pickle的默认格式了,pickle的二进制格式支持不错.这点在你向数据库里面存东西是尤为突出,把它们作为BLOB字段存储而不是作为TEXT或者VARCHAR字段存储要好很多.万一有人把你的字段改成了Unicode类型,这可以避免pickle的崩溃. 另外,使用第三方模块时要注意Unicode通讯方面遇到麻烦,要设置好环境中相应的参数设置 正则表达式引擎需要Unicode支持.详见6.9节的re模块 常用Unicode编辑码 编码描述 utf-8变量长度为8的编码(默认编码) utf-16变量长度为16的编码(大/小端) utf-16-le小端UTF-16编码 utf-16-be大端UTF-16编码 ascii7-bit7位ASCII码表 iso-8859-1ISO8859-1(Latin-1)码表 unicode-escape(定义见PythonUnicode构造函数) raw-unicode-escape(定义见PythonUnicode构造函数) nativePython用的内部格式 模块描述 re正则表达式:强大的字符串模式 struct字符串和二进制之间的转换 c/StringIO字符串缓冲对象,操作方法类 base64Base16,32,64数据编解码 codecs解码器注册和基类 crypt进行单方面加密 diffliba找出序列间的不同 hashlib多种不同安全哈希算法和信息摘要 hmaHMAC信息鉴权算法的Python md5RSA的MD5信息摘要鉴权 rotor提供多平台的加解密服务 shaNIAT的安全哈希算法SHA stringprep提供用于IP协议的Unicode字符串 textwrape文本打包和填充 unicodedataUnicode数据库 不需要像C一样添加结束符,python自动管理,字符串中只包含你所定义的东西,没有别的。 Python中没有特定用于列表的内建函数。只有range()函数接受一个数值作为输入,输出一个符合标准的列表. 列表类型支持的所有方法: list.append(obj)向列表中添加一个对象obj list.count(obj)返回一个对象obj在列表中出现的次数 list.extend(seq)把序列seq的内容添加到列表中 list.index(obj,i=0,j=len(list))返回list[k]==obj的k值,并且k的范围在i<=k 引发ValueError异常. list.insert(index,obj)在索引量为index的位置插入对象obj. list.pop(index=-1)删除并返回指定位置的对象,默认是最后一个对象 list.remove(obj)从列表中删除对象obj list.reverse()原地翻转列表 list.sort(func=None,key=None,reverse=False)以指定的方式排序列表中的成员,如果func和key参数指定,则按照指定的方式比较各个元素,如果reverse标志被置为True,则列表以反序排列. python方法不一定有返回值,如sort(),extend()和reverse()这些操作在列表中原地执行操作,原列表内容被改变,没有返回值。与之相反,字符串不能被改变,所以这些函数产生新对象,一定会有返回值。 元组也没有它自己专用的运算符和内建函数,因为元组是不可变的,没有实现排序,替换,添加等方法 但元组也可以间接的变化,如两个元组用加号+连接;或者元组元素为列表,就可以增减元素。 注意,有符号封装的多对象集合其实是返回的一个单一的容器对象,如 deffoo1(): : returnobj1,obj2,obj3#等同于return(obj1,obj2,obj3) 'xyz' >>>type(('xyz'))#astring,notatuple 数组一种受限制的可变序列类型,要求所有的元素必须都是相同的类型 copy提供浅拷贝和深拷贝的能力 operator包含函数调用形式的序列操作符,比如operator.concat(m,n)就相当于连接操作(m+n)。 rePerl风格的正则表达式查找(和匹配);见第15章 StringIO/cStringIO把长字符串作为文件来操作,比如read(),seek()函数等,C版的更快一些,但是它不能被继承. Textwrap用作包裹/填充文本的函数,也有一个类 types包含Python支持的所有类型 collections高性能容器数据类型 copy模块中只有两个函数可用: (1)copy()进行浅拷贝操作 (2)deepcopy()进行深拷贝操作 浅拷贝:没有申请新内存,新指针(地址)与原指针都指向一个内存,原来对象的内存。 也就是说,新创建了一个类型跟原对象一样,其内容是原来对象元素的引用,换句话说,这个拷贝的对象本身是新的,但是它的内容不是. 序列类型对象默认拷贝是浅拷贝,主要有以下几种方式实施: (1)完全切片操作[:], (2)利用工厂函数,比如list(),dict()等 (3)使用copy模块的copy函数 深拷贝:又叫完全拷贝。新申请内存,新指针(地址)指向新内存,新对象完全独立于老对象。 第一,非容器类型没有被拷贝一说,如数字,字符串和其他"原子"类型的对象,像代码,类型和xrange对象等,而浅拷贝是用完全切片操作来完成的 第二,如果元组变量只包含原子类型对象,那么深拷贝也相当于浅拷贝.因为内部是非容器类对象,python缓存了对象,所以只有一个内存空间。 如,我们把账户信息改成元组类型,那么即便按我们的要求使用深拷贝操作也只能得到一个浅拷贝: >>>person=['name',('savings',100.00)] >>>newPerson=copy.deepcopy(person) >>>[id(x)forxinperson,newPerson] [12225352,12226112] >>>[id(x)forxinperson] [9919616,11800088] >>>[id(x)forxinnewPerson] 总之, a.只有容器类才有拷贝概念,分深拷贝和浅拷贝; b.非容器类不分,都是python缓存对象共享一个地址如字符串、数字; c.复合容器(如list元素是元组,而元组的元素是list)的copy,其外部和内部对象分别对应自身对象的copy机制,外部list自身可以是深拷贝,但内部元组元素共享缓存独享(类似浅拷贝)、而外部元组类似浅拷贝时,内部list对象元素是深拷贝,代码如下: importcopy tuple1=([1,2,3],'a','b') tuple3=tuple1#浅拷贝 tuple4=copy.deepcopy(tuple1)#深拷贝 print[id(x)forxintuple1] print[id(x)forxintuple3] print[id(x)forxintuple4] 输出结果为: [40129800L,38969632L,39037848L] [40558664L,38969632L,39037848L] 23、string、tuple、list的built-in函数 三者都支持的共享函数: cmp() len() list() max() min() [:]slice切片符号 * + In notin 只有string和list共同支持的函数: count() index() .attributes属性提取符号 另外,insert()、append()、extend()三者只有list支持。三者都是添加操作,前两个是添加单个元素,extend()是添加另一个list对象,相当于“+”操作符功能。 剩下的其他内建函数只有string支持,如zfill()、upper()、%、ord()、oct()、hex()、find()、expandtabs()、cpitalize()、center()、chr()、decode()、encode()、endswith()等等。 dict1={} dict2={'name':'earth','port':80} dict3=dict((['x',1],['y',2])) 注意用dict方法建立字典对象,可用于对象间的转化,转化list对象,然后转化为字典。 内建方法fromkeys()创建元素具有相同的值的字典(未给出,默认为None): >>>ddict={}.fromkeys(('x','y'),-1) >>>ddict {'y':-1,'x':-1} >>>edict={}.fromkeys(('foo','bar')) >>>edict {'foo':None,'bar':None} forkeyindict2.keys(): ...print'key=%s,value=%s'%(key,dict2[key]) 或者简化直接用字典名 forkeyindict2: 3、判断元素村子尽量使用in和notin,不用has_key() 'name'indict2 4、删除字典元素和字典 deldict2['name']#删除键为“name”的条目 dict2.clear()#删除dict2中所有的条目 deldict2#删除整个dict2字典 dict2.pop('name')#删除并返回键为“name”的条目 5、请不要用内建类型为变量命名,如dict,list,file,bool,str,input,len 6、字典比较 先长度,然后逐个元素,先比较key,在比较value,谁大立刻返回1、0、-1 7、hash() 返回参数对象的哈希值。不是为字典设计的方法,可以判断某个对象是否可以做一个字典的键。 Set内部元素无序,所以不可以为集合创建索引或执行切片(slice)操作,也没有键(keys)可用来获取集合中元素的值。 可变集合(set):可添加删除元素 不可变集合(frozenset):不可以添加删除元素 工厂方法set()和frozenset(): 参数必须是可迭代的,即,一个序列,或迭代器,或支持迭代的一个对象,例如:一个文件或一个字典 >>>s=set('cheeseshop') >>>s set(['c','e','h','o','p','s']) >>>t=frozenset('bookshop') >>>t frozenset(['b','h','k','o','p','s']) >>>type(s) >>>type(t) 作用函数len()、==、in、notin: 例如:foriins: ...printi 添加、删除元素: >>s.add('z') set(['c','e','h','o','p','s','z']) >>>s.update('pypi') set(['c','e','i','h','o','p','s','y','z']) >>>s.remove('z') set(['c','e','i','h','o','p','s','y']) >>>s-=set('pypi') set(['c','e','h','o','s']) 不可变集合不能添加、删除元素,会报错 t.add('z') Traceback(mostrecentcalllast): AttributeError:'frozenset'objecthasnoattribute'add' 删除:dels 是判断两集合是超集或子集。只跟集合中元素组成有关,与元素顺序、集合长度等其他无关 “小于”符号(<,<=)用来判断子集; “大于”符号(>,>=)用来判断超集。 >>>set('shop') >>>set('bookshop')>=set('shop') 在while和for循环中使用else语句,else子句在循环完成后,最后执行,如果有break语句则会跳过else块。 迭代器一组数据结构,利用引从0开始一直"迭代"到序列的最后一个条目。支持多种对象,如字典,类对象。提升性能。 迭代通过对象的next()方法,而不是通过索引来计数,迭代全部完成后发出StopIteration异常作为结束标志,不是报错。代码如下 fetch=iter(seq) whileTrue: i=fetch.next() exceptStopIteration: do_something_to(i) 文件迭代 用reachLineinmyFile或者foreachLineinmyFile.readlines()都可以。如 myFile=open('config-win.txt') foreachLineinmyFile: ...printeachLine,#commasuppressesextra\n Listcomprehensions,或缩略为listcomps,简单实用的工具,用来动态地创建列表。 语法:exprforiter_variniterable 其中,expr是一个表达式,完成计算。 列表解析的表达式可以取代内建函数,而且效率更高。如map()、lambda、filter()等,被简化为一个列表解析式,函数功能: map()对所有的列表成员应用一个操作 filter()基于一个条件表达式过滤列表成员 lambda允许你快速地创建只有一行的函数对象 例子: map(lambdax:x**2,range(6)) 可以简化为:[x**2forxinrange(6)] 扩展语法: [exprforiter_variniterableifcond_expr] 例子,判断奇数: >>>seq=[11,10,9,9,10,10,9,8,23,9,7,18,12,11,12] >>>filter(lambdax:x%2,seq) [11,9,9,9,23,9,7,11] 用列表解析: >>>[xforxinseqifx%2] 三行五列的矩阵 >>>[(x+1,y+1)forxinrange(3)foryinrange(5)] [(1,1),(1,2),(1,3),(1,4),(1,5),(2,1),(2,2),(2,3),(2,4),(2,5),(3,1),(3,2),(3,3),(3,4),(3,5)] 计算出所有非空白字符的数目,把每行分割(split)为单词 >>>f=open('hhga.txt','r') >>>len([wordforlineinfforwordinline.split()]) 计算文件大小 importos >>>os.stat('hhga.txt').st_size 499L 列表解析统计非空字符(去空格)为 >>>f.seek(0) >>>sum([len(word)forlineinfforwordinline.split()]) 408 处理大文件时readlines()会读取文件的所有行,用迭代器,生成器表达式替换列表解析,比如用max()内建函数得到最长的字符串长度: f=open('/etc/motd','r') allLineLens=[len(x.strip())forxinf] f.close() returnmax(allLineLens) 用生成器表达式简化,移到max()中 longest=max(len(x.strip())forxinf) returnlongest 文件只是连续的字节序列.数据的传输经常会用到字节流,无论字节流是由单个字节还是大块数据组成. open()和file()一样,可相互替换。 出错产生IOError异常 建议使用open()读写文件,在在处理文件对象时使用file(),例如ifinstance(f,file). write()或writelines()不会自动加入行结束符。因为read的时候不删除,所以自带。如没有必须自己加上。 seek()方法,参数offset 默认值为0代表文件开头 1代表从当前位置算起, 2代表从文件末尾算起 text()返回前文件指针在文件中的位置。从文件起始算起,单位为字节。 目前,使用文件迭代是最高效的方法,直接 foreachLineinf: 而老的方法file.xreadlines()最高效。 最差file.readlines()会一次读入所有行到一个列表,需要大内存。内存不足时,用readline()一次读入一行,但效率非常慢。遇到foreachLineinf.readline(),全部修改成文件迭代方式。 file.fileno()返回文件的描述符(filedescriptor,FD,整数 file.flush()刷新文件的内部缓冲区 file.isatty()判断file是否是一个类tty设备 file.next()返回文件的下一行(类似于file.readline()),或在没有其它行时引发StopIteration异常 file.seek(off,whence=0)在文件中移动文件指针,从whence(0代表文件其始,1代 表当前位置,2代表文件末尾)偏移off字节 file.tell()返回当前在文件中的位置 file.truncate(size=file.tell())截取文件到最大size字节,默认为当前文件位置 file.closedTrue表示文件已经被关闭,否则为False file.encoding文件所使用的编码-当Unicode字符串被写入数据时,它们将自动使用file.encoding转换为字节字符串;若file.encoding为None时使 用系统默认编码 file.mode文件打开时使用的访问模式 file.name文件名 file.newlinesa未读取到行分隔符时为None,只有一种行分隔符时为一个字符串,当文件有多种类型的行结束符时,则为一个包含所有当前所遇到的行结束符的列表 file.softspace为0表示在输出一数据后,要加上一个空格符,1表示不加。这个属性 程序一执行,那么你就可以访问三个标准文件。分别是标准输入(一般是键盘),标准输出(到显示器的缓冲输出)和标准错误(到屏幕的非缓冲输出),对应为stdin,stdout和stderr。 (将多个函数的相同功能代码提取成一个装饰函数,用@+函数名放在函数前直接调用,实际是将被装饰函数作为参数传入装饰函数中,返回新的参数对象,原有被装饰函数对象作废) 类似于Java的AOP(AspectOrientedProgramming,面向方面编程) 一个用来包装函数的函数,返回一个修改之后的函数对象,将其重新赋值原来的标识符,并永久丧失对原始函数对象的访问。 用途: 引入日志、 增加计时逻辑来检测性能、 给函数增加事务的能力。 简单说,为已经存在的对象添加额外的功能。在函数执行前和执行后分别附加额外功能。 也就是,装饰函数的参数是被装饰的函数对象,返回原函数对象,实际上为myfunc=deco(myfunc),比如下面代码 1.defdeco(func): 2.printfunc 3.returnfunc 4.@deco 5.deffoo():pass 6.foo() 实际代码是foo=deco(foo) 普通装饰器,就是定义一个装饰函数名,以作用函数(需要包装的函数)为参数,内部定义封闭函数,也就是返回定义函数对,代码如下,看最后一行,返回内部封闭函数对象: defdecorator(F): defnew_F(a,b): print("input",a,b) returnF(a,b) returnnew_F 如果装饰函数需要参数,而被装饰函数也有参数,就做三层包装: #anewwrapperlayerdefpre_str(pre=''):#olddecoratordefdecorator(F):defnew_F(a,b):print(pre+"input",a,b)returnF(a,b)returnnew_Freturndecorator#getsquaresum@pre_str('^_^')defsquare_sum(a,b):returna**2+b**2 参数'^_^'是装饰函数的参数,F是被装饰函数名,而内部是包装的执行函数。也就是说有参数传入加一层。 在函数内部定义一个内部函数(嵌套函数),其引用了外部作用域的变量,并且不是全局变量,那么这个内部函数叫闭包。装饰器就是闭包。 函数调用自身叫递归,典型例子,阶乘factorial(N)=N*factorial(N-1),求N项值需要知道N-1项值。 生成器是带yield语句的函数: (其实生成器对象就是有next()函数,每次调用直接返回yield后面的对象,也就是说yield是next()函数的返回标志,简单用途如每次返回列表第一个位置的元素) 能暂停执行并返回一个中间的结果(yield语句部分的功能:返回一个值给调用者并暂停执行),当调用next()方法时,会准确地从离开地方继续执行(当它将返回值和控制传递给调用者时)。而普通函数或者子程序只返回一次。 从_future_模块中导入generators来用生成器,从2.3开始直接用。 简单的生成器: defsimpleGen(): yield1 yield'2-->punch!' 调用方法和执行结果: myG=simpleGen() myG.next() 输出:1 输出:'2-->punch!' 输出:Traceback(mostrecentcalllast): File"",line1,inmyG.next()StopIteration 遇到next()没有值可返回,就抛出异常StopIteration。 (1)在交互式解释器会话中,“_”代表上一条执行的语句的结果。 (2)“_”作为临时性的名称使用,就是不会在后面再次用到该名称,而临时分配了一个特定的名称。如 n=42 for_inrange(n): do_something() (3)“_”作为一个函数来使用,如Django文档“转换”章节中的代码。这样用法易冲突,尽量不用。 (4)在程序代码中用法三种: _xxx不能用'frommoduleimport*'导入 __xxx__系统定义名字(程序员自己不要这样命名) __xxx类中的私有变量名(自动进行私有转换Privatenamemangling) 核心风格:避免用下划线作为变量名的开头。其他下划线用法都是为了避免命名重复。具体解释如下: 名称前的单下划线,类似一种惯例,指定该属性为“私有”,只供内部使用。 名称前的双下划线(如:__shahriar)为了避免与子类定义的名称冲突,私有变量名字改编(Privatenamemangling),即在代码生成之前被转换为长格式(变为公有),也就是变量前端加上下划线字符和类名“_类名”。代码实例如,有类A, >>>classA(object): ...def_internal_use(self): ...pass ...def__method_name(self): ... >>>dir(A()) ['_A__method_name',...,'_internal_use'] 在设计继承类B: >>>classB(A): >>>dir(B()) ['_A__method_name','_B__method_name',...,'_internal_use'] a.py导入了模块b.py,而修改b.py的过程中添加导入模块a.py,就会报错,这是循环导入错误。 Import都是在a.py和b.py的文件开头。 解决办法有两个: 1,移除一个导入语句 2,将b.py的import语句放入函数内部。不要放在开头。 封装:数据属性对外隐藏,自身设计访问方法供外部使用 合成:将多个类合成一个类 泛化:提取共性做成父类 特化:设计新功能的子类 多态:调用不同对象的相同名称的函数,却具有不同的功能。 自省或反射:给出自身信息的功能,如提供结构,参数,对应函数等信息。 类方法是类内部定义的的函数,不是实例属性,是类属性; 存在实例后,方法才能绑定到类实例上,调用时通过类实例调用; 类中,任何方法定义中第一个参数都是变量self。 绑定方法的不同在于与实例绑定,所以调用绑定方法通过实例,不需要给出self参数。 而非绑定方法直接通过类调用(类名加点),且没有实例必须传递self参数。主要场景 派生一个子类要覆盖父类的方法,如构造方法 classEmplAddrBookEntry(AddrBookEntry): def__init__(self,nm,ph,em): AddrBookEntry.__init__(self,nm,ph) self.empid=id self.email=em其中,EmplAddrBookEntry是AddrBookEntry的子类,其重载了构造器__init__(),其中调用父类的构造器时没有父实例,明确的给出self参数。 Python类定义中,方法的第一参数是self,用于传递对象本身,调用时不显示传递。 而在子类中调用父类时,最简单的方法是把对象调用转换成类调用,此时,self参数必须显示传递。也就是说,子类定义时,使用super()调用父类时必须显示传递self参数,如 classFooParent: defbar(self,message): print(message) classFooChild(FooParent): super(FooChild,self).bar(message)#也可是FooParent.bar(self,message) 调用代码:FooChild().bar("Hello,World.") 其中,子类定义中使用super函数 第一参数是当前子类, 第二参数self 多重继承在super机制里可保证公共父类仅被执行一次,至于执行的顺序按照mro进行的,myclass.__mro__的属性 注意super继承只能用于新式类,用于经典类时就会报错。 新式类:必须有继承的类,如果没什么想继承的,那就继承object 经典类:没有父类,如果此时调用super就会出现错误:『super()argument1mustbetype,notclassobj』 C.__len__(self)mapping中的项的数目 C.__hash__(self)散列(hash)函数值 C.__getitem__(self,key)得到给定键(key)的值 C.__setitem__(self,key,val)设置给定键(key)的值 C.__delitem__(self,key)删除给定键(key)的值 C.__missing__(self,key)给定键如果不存在字典中,则提供一个默认值 C.__*add__(self,obj)串连;+操作符 C.__*mul__(self,obj)重复;*操作符 其中,星号通配符标注的数值二进制操作符则表示这些方法有多个版本,在名字上有些许不同。 "*"代表''(selpOPobj),'r'(objOPself),或'i'(原位(in-place)操作,Py2.0新增), 例如__add__,__radd__,or__iadd__. “*”eithernothing(selfOPobj),“r”(objOPself),or“i”forin-place operation(newinPython1.6),i.e.,__add__,__radd__,or__iadd__. 实现这些特殊方法将会重载操作符,使它们可以处理你的类类型的实例。比如实例之间的+加号功能通过__add__()实现,而累加通过__iadd__(),右结合加号通过__radd__()实现。 从集合的第一个元素开始访问,直到所有的元素都被访问一遍后结束。 不能回退或者随机访问,只能往前进行迭代 不是线程安全的,在多线程环境中对可变集合使用迭代器是一个危险的操作,使用时小心。 优点: 是不要求事先准备好整个迭代过程中所有的元素。仅仅在迭代至某个元素时才计算该元素,而在这之前或之后,元素可以不存在或者被销毁。这个特点使得它特别适合用于遍历一些巨大的或是无限的集合,比如几个G的文件,或是斐波那契数列等等。这个特点被称为延迟计算或惰性求值(Lazyevaluation)。 统一的访问集合的接口。只要是实现了__iter__()方法的对象,就可以使用迭代器进行访问。 Python专门将关键字for用作了迭代器的语法糖。在for循环中,Python将自动调用工厂函数iter()获得迭代器,自动调用next()获取元素 自己设计迭代器: 迭代器有两个基本方法: 1)next方法:返回容器的下一个元素2)__iter__方法:返回迭代器自身 在类的__iter__方法中返回一个对象,这个对象拥有一个next()方法,这个方法能在恰当的时候抛出StopIteration异常即可。但是需要自己实现迭代器的时候不多,即使需要,使用生成器会更轻松 包装,是将一段代码重新功能封装,去除不要的,加新的,保留原有的。 派生是对类的包装。 classWrapMe(object): def__init__(self,obj): self.__data=obj defget(self): returnself.__data def__repr__(self): return‘self.__data‘ def__str__(self): returnstr(self.__data) def__getattr__(self,attr): returngetattr(self.__data,attr) 例子中,可以看到将原始对象包装好后,给出__getattr__,比如