0.说明
说对象是面向对象编程语言最重要的一部分一点也不为过,没有了“对象”,面向对象将无从谈起。Python也是如此,如果无法掌握对象,你很难有大的进步与提升。
1.Python对象
(1)对象特性
Python使用对象模型来存储数据,构造任何类型的值都是一个对象,所有的Python对象都拥有下面的三个特性:
对于身份特性,它是可读的;对于类型特性,新式类型和类可以修改,但不建议初学者这样做,另外Python有一系列的基本(内建)数据类型,可以自己定义(一般推荐通过创建和实例化类来对特定的数据进行存储);对于值,取决于该对象是否支持更新操作。
(2)对象属性
Python使用句点标记法来访问属性,最常用的属性是函数和方法,当然一些Python对象也有数据属性。
2.标准类型
需要注意的是,使用上面这些基本类型所构造的值都为该类型对应的对象。
3.其他内建类型
(1)类型对象和type类型对象
前面提到,对象有一系列行为和特性,而这些信息就是保存在对象的类型当中:
1
2
|
>>> type ( 42 )
< type 'int' >
|
type()返回的是一个类型对象,表明42是一个数字类型对象,而<type 'int'>本身也有所属于的类型,可以继续使用type()来查看:
1
2
|
>>> type ( type ( 42 ))
< type 'type' >
|
<type 'type'>表示<type 'int'>是一个type类型对象,尝试继续使用内建函数type()来作进一步操作:
1
2
|
>>> type ( type ( type ( 42 )))
< type 'type' >
|
得到的还是type类型对象,于是可以有下面的结论:
(2)None:Python的Null对象
Python有一个特殊的类型,被称为Null对象或者NoneType,它只有一个值,那就是None
1
2
3
|
>>> None
>>> type ( None )
< type 'NoneType' >
|
None没有什么有用的属性,它的布尔值总是False。
(3)布尔值
前面提及布尔值,有以下几点注意:
4.内部类型
(1)代码对象
代码对象是编译过的Python源代码片段,它是可执行对象,通过调用内建函数compile()可以得到,然后可以被exec命令或eval()内建函数来执行。
代码对象本身不包含任何执行环境信息,它是用户自定义函数的核心,在被执行时动态获得上下文(事实上代码对象是函数的一个属性)。一个函数除了有代码对象属性以外,还有一些其他函数必须的属性,包括函数名 文档字符串 默认参数及全局命名空间等。
(2)帧对象
帧对象表示Python的执行栈帧。帧对象包含Python解释器在运行时所需要知道的所有信息,它的属性包含下面这些信息:
-
指向上一帧的链接
-
正在被执行的代码对象
-
本地及全局名称空间字典及当前指令等
每次函数调用产生一个新的帧,每一个帧对象都会相应创建一个C栈帧,用到帧对象的一个地方是跟踪记录对象。
(3)跟踪记录对象
当异常发生时,一个包含针对异常的栈跟踪信息的跟踪记录对象被创建。如果一个异常有自己的处理程序,处理程序就可以访问这个跟踪记录对象。
(4)切片对象
当使用Python扩展的切片语法时,就会创建切片对象。
(5)省略对象
省略对象用于扩展切片语法中,起记号作用。这个对象在切片语法中表示省略号。类似Null对象None,省略对象有一个唯一的名字Ellipsis:
1
2
3
4
|
>>> Ellipsis
Ellipsis
>>> type (Ellipsis)
< type 'ellipsis' >
|
它的布尔值始终为True。
(6)Xrange对象
调用内建函数xrange()会生成一个Xrange对象,xrange()是内建函数range()的兄弟版本,用于需要节省内存使用或range()无法完成的超大数据集场合。
5.标准类型操作符
(1)对象值的比较
比较操作符用来判断同类型对象的值是否相等,所有的内建类型(前面所说的标准类型和其他内建类型)均支持比较运算,比较运算结果返回布尔值True或False。
注意:比较操作是针对对象的值进行的,就就是说比较的是对象的数值而不是对象本身。
另外提及Python的一个特性,多个操作可以在同一行上进行,求值顺序为从左到右:
等价于:
(2)对象身份比较
在Python中,应该将变量名看成是对象的一个链接,对对象的一个引用,它被指向这个对象,而不是直接赋值为该对象。可以使用内建函数id()或关键字is和is not来比较两个对象身份:
1
2
3
4
5
|
>>> foo1 = foo2 = 4.3
>>> a is b
True
>>> id (a) = = id (b)
True
|
1
2
3
4
5
6
7
8
|
>>> foo1 = 4.3
>>> foo2 = 1.3 + 3.0
>>> foo1 is foo2
False
>>> id (foo1)
18024120
>>> id (foo2)
18024048
|
在Python中,有一个'仅缓存简单整型'的概念,即对于一些简单的不可变对象,比如整型对象和字符串对象,Python会先将它们缓存到内存中,当需要就直接被引用,而无需创建,可以看下面的例子:
1
2
3
4
5
6
7
8
9
10
11
12
|
>>> a = 1
>>> id (a)
17953112
>>> b = 1
>>> id (b)
17953112
>>> c = 1.0
>>> id (c)
18024096
>>> d = 1.0
>>> id (d)
18024072
|
当然,只是缓存简单整型:
1
2
3
4
5
6
|
>>> e = 336
>>> id (e)
18554008
>>> f = 336
>>> id (f)
18601504
|
理解起来相对是比较简单的了。
(3)布尔类型
按优先级从高到低,主要是:
6.标准类型内建函数
即用于操作基本肉类的内建函数,如下:
-
cmp(obj1, obj2):大于返回负数,小于返回正数,等于返回0
-
repr(obj)或`obj`:返回一个对象的字符串表示
-
str(obj):返回对象适合可读性好的字符串表示
-
type(obj):得到一个对象的类型,并返回相应的类型对象(type对象,与type类型对象不同)
(1)type()
接受一个对象作为参数,并返回它的类型,它的返回值是一个类型对象:
1
2
3
4
5
6
|
>>> type ( 4 )
< type 'int' >
>>> type ( 'Hello World!' )
< type 'str' >
>>> type ( type ( 4 ))
< type 'type' >
|
以<>语法表示的,说明其是一个对象,每个对象都可以实现一个可打印的字符串表示。但对于那些不容易显示的对象来说,Python会以一个相对标准的格式来表示这个对象,如:<object_something_or_another>,其中提供了对象类别 对象id或位置等信息。
(2)cmp()
例子如下:
1
2
3
4
5
6
7
8
9
10
|
>>> cmp ( 1 , 2 )
- 1
>>> cmp ( 2 , 1 )
1
>>> cmp ( 2 , 2 )
0
>>> cmp ( 'abc' , 'xyz' )
- 1
>>> cmp ( 'abc' , 'abc' )
0
|
比较是在对象之间进行的,不管是标准类型对象还是用户自定义对象,如果是用户自定义对象,cmp()会调用该类的特殊方法__cmp__()。
(3)str()和repr()(或``操作符)
str()和repr()或``用来以字符串方式获取对象的内容 类型和数值等信息,作如下说明:
1
2
3
4
5
6
7
8
|
>>> str ( 1 )
'1'
>>> eval ( str ( 1 ))
1
>>> str ([ 1 , 2 , 3 ])
'[1, 2, 3]'
>>> eval ( str ([ 1 , 2 , 3 ]))
[ 1 , 2 , 3 ]
|
1
2
3
4
5
6
7
8
9
10
11
|
>>> repr ([ 1 , 2 , 3 ])
'[1, 2, 3]'
>>> eval ( repr ([ 1 , 2 , 3 ]))
[ 1 , 2 , 3 ]
>>> eval ( repr ( type ( 42 )))
Traceback (most recent call last):
File "<stdin>" , line 1 , in <module>
File "<string>" , line 1
< type 'int' >
^
SyntaxError: invalid syntax
|
总的来说,repr()输出对Python比较友好,而str()输出对用户比较友好。
(4)type()和isinstance()
1
2
3
4
5
6
7
8
|
>>> class Foo: pass
...
>>> class foo( object ): pass
...
>>> type (Foo)
< type 'classobj' >
>>> type (foo)
< type 'type' >
|
type(foo)的输出之所以会这样,是因为类就是类型。
-
isinstance()
如果需要判断一个对象的类型,可以使用下面的方法:
1
2
3
|
>>> from types import IntType
>>> type ( 42 ) = = IntType
True
|
当使用isinstance()时,就会方便很多:
1
2
3
4
5
|
>>> if isinstance ( 42 , ( float )): print 'OK'
...
>>> if isinstance ( 42 , ( float , int )): print 'OK'
...
OK
|
isinstance()第一个参数为一个对象,第二个参数为一个类型对象或一个类型对象的元组(这样的话,就可以一次与多个类型对象作比较了,省去了多个if-else语句)。
7.类型工厂函数
因为从Python2.2开始,类和类型就统一了,也就是说,所有的内建类型其实也都是类。而原来的转换函数int() type() list()等,现在都成了工厂函数,说是函数,实质上他们也是类,调用它们时,实际上就生成了该类型的一个实例,就像工厂生产货物一样(这就是工厂模式的概念,在做大型程序的开发时,该设计思想很经常会用到)。
对于Python已给出的工厂函数(实质是类),可以查看书本P71,下面只给出作为示范:
-
int(), long(), float(), complex()
-
str(), unicode, basestring()
-
list(), tuple()
-
type()
8.标准类型的分类
标准类型:基本内建数据对象原始类型,解释如下:
当然,我们可以对标准类型进行分类,以便于我们更好地理解这些标准类型的特性。
(1)存储模型
分类标准:看这种类型的对象能保存多少个对象。于是会有下面两种情况:
-
原子/标量存储:能保存单个字面对象的类型
-
容器存储:可容纳多个对象的类型
分类如下:
存储模型
|
分类 |
Python类型 |
标量/原子类型 |
数值(所有的数值类型),字符串(全部是文字) |
容器类型 |
列表 元组 字典
|
其中对于容器对象(也就是列表等这些类型的一个实例对象了),它们都能容纳不同类型的对象。另外需要注意的是字符串,因为在Python中并没有“字符”类型的数据结构,所以字符串是一个自我包含的文字类型。
(2)更新模型
分类标准:值是否可改变。于是会有下面两种情况:
-
可变类型:对象的值可以被更新
-
不可变类型:对象的值不可以被更改
分类如下:
更新模型
|
分类 |
Python类型 |
可变类型 |
列表 字典 |
不可变类型 |
数字 字符串 元组
|
数字或字符串是不可变类型,也许难以理解,但可以看下面的例子:
1
2
3
4
5
6
7
8
9
10
11
12
|
>>> a = 3
>>> id (a)
17953064
>>> a = 6
>>> id (a)
17952992
>>> x = 'abc'
>>> id (x)
140407360100672
>>> x = 'change'
>>> id (x)
140407359514784
|
也就是说,表面上值是改变了,但实际上是3这个数字对象被丢弃回收,然后创建了一个新的数字对象6。而对于字符串类型,这也充分说明了在Python中是没有字符类型这一数据结构的。
但对于可变类型,情况就不一样了:
1
2
3
4
5
6
|
>>> aList = [ 1 , 2 , 3 ]
>>> id (aList)
140407359478888
>>> aList.append( 'change' )
>>> id (aList)
140407359478888
|
(3)访问模型
分类标准:如何访问存储的数据。于是会有下面三种情况:
-
直接存取:非容器类型可以直接访问(对于字符串,会有些特别,所以不会属于此类)
-
顺序/序列:也就是可以通过使用切片(slice)的方式来进行访问
-
映射:元素是无序存放的,但可以通过键值对的方式进行访问
分类如下:
访问模型
|
分类 |
Python类型 |
直接访问 |
数字 |
顺序访问 |
字符串 列表 元组
|
映射访问 |
字典 |
虽然字符串是非容器类型,但由于可以使用切片的方式对它进行访问,所以归类到顺序访问。
将上面的三种分类模型和Python对应的数据结构进行总结,可如下:
标准类型分类
|
数据类型 |
存储模型 |
更新模型 |
访问模型 |
数字 |
标量 |
不可更改 |
直接访问 |
字符串 |
标量 |
不可更改 |
顺序访问 |
列表 |
容器 |
可更改 |
顺序访问 |
元组 |
容器 |
不可更改 |
顺序访问 |
字典 |
容器 |
可更改 |
映射访问 |
9.不支持的类型
(1)char
在C语言中会有这种数据类型,但在Python中,则没有。
(2)指针
Python的垃圾收集器会替我们管理这些工作,不用担心。
(3)int short long
只需要知道,在Python中,直接使用整型就可以了,因为如果超出了范围,Python会为我们自动转换。
(4)float double
Python的浮点类型实际是C语言的双精度浮点类型。如果需要更高的精度(处理与金钱相关的数据时),可以使用Python的十进制海战型类型Decimal,只需要导入decimal模块就可以使用。一般情况下,默认的float类型就足够用了。
需要强调的是,对象的概念无论是在Python还是在其他的面向对象编程语言中,都是十分重要的,如果无法掌握对象,那么也就不能充分利用面向对象编程语言的特性。