Python 对象
Python 使用对象模型来存储数据。构造任何类型的值都是一个对象。
所有的 Python 对像都拥有三个特性:身份,类型和值。身份
每一个对象都有一个唯一的身份标识自己,任何对象的身份可以使用内建函数id()来得到。这个值可以被认为是该对象的内存地址。
类型
对象的类型决定了该对象可以保存什么类型的值,可以进行什么样的操作,以及遵循什么样的规则。您可以用内建函数 type()查看 Python 对象的类型。因为在 Python 中类型也是对象,所以type()返回的是对象而不是简单的 字符串。
值
对象表示的数据项
上面三个特性在对象创建的时候就被赋值,除了值之外,其它两个特性都是只读的。对于 新风格的类型和类, 对象的类型也是可以改变的。
类型对象和type类型对象
虽然看上去把类型本身也当成对象有点特别,我们 还是要在这里提一提。你一定还记得,对象的一系列固有行为和特性(比如支持哪些运算,具 有哪些方法)必须事先定义好。从这个角度看,类型正是保存这些信息的最佳位置。描述一种 类型所需要的信息不可能用一个字符串来搞定,所以类型不能是一个简单的字符串,这些信息 不能也不应该和数据保存在一起, 所以我们将类型定义成对象。
下面我们来正式介绍内建函数type()。通过调用 type()函数你能够得到特定对象的类型 信息:1
2>>> type(42)
您看到的实际上是一个类型对象,碰巧它输出了一个字符串来告诉你 它是个int 型对象。
那么类型对象的类型是什么?1
2>>> type(type(42))
没错,所有类型对象的类型都是 type,它也是所有 Python 类型的根和所有 Python 标准类 的默认元类(metaclass)。
None,Python 的 Null 对象
Python有一个特殊的类型,被称作 Null 对象或者 NoneType,它只有一个值,那就是 None。 它不支持任何运算也没有任何内建方法。如果非常熟悉 C 语言,和 None 类型最接近的 C 类型就 是 void,None 类型的值和 C 的 NULL 值非常相似(其他类似的对象和值包括 Perl 的 undef 和 Java 的 void 类型与 null 值)。
None 没有什么有用的属性,它的布尔值总是 False。
对象的布尔值
所有标准对象均可用于布尔测试,同类型的对象之间可以比较大小。
每个对象天生具有布 尔 True 或False 值。空对象、值为零的任何数字或者 Null 对象 None 的布尔值都是 False。
下列对象的布尔值是 False。None
False (布尔类型)
所有的值为零的数
0 (整型)
0.0 (浮点型)
0L (长整型)
0.0+0.0j (复数)
"" (空字符串)
[] (空列表)
() (空元组)
{} (空字典)
set()(空集合)
值不是上面列出来的任何值的对象的布尔值都是 True,例如 non-empty、non-zero 等等。
用户创建的类实例如果定义了 nonzero(__nonzero__())或length(__len__())且值为 0,那 么它们的布尔值就是False。
标准类型运算符
对象值的比较
比较运算符用来判断同类型对象是否相等,所有的内建类型均支持比较运算,比较运算返 回布尔值 True 或 False。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
162 == 2
True
2.46 <= 8.33
True
5+4j >= 2-3j
True
'abc' == 'xyz'
False
'abc' > 'xyz'
False
>>>'abc' < 'xyz'
True
>>>[3, 'abc'] == ['abc', 3]
False
>>>[3, 'abc'] == [3, 'abc']
True
不同于很多其它语言,多个比较操作可以在同一行上进行,求值顺序为从左到右。1
2
3
4
5
6>>>3 < 4 < 7
True
>>>4 > 3 == 3 #sameas(4>3)and(3==3)
True
>>>4 < 3 < 5 != 2 < 7
False
其实这个表达式本质上是由 多个隐式的 and 连接起来的多个表达式。1
2>>>3 < 4 < 7 #sameas"( 3 < 4 ) and ( 4 < 7 )"
True
我们会注意到比较操作是针对对象的值进行的,也就是说比较的是对象的数值而不是对象 本身。
对象身份比较
作为对值比较的补充,Python 也支持对象本身的比较。对象可以被赋值到另一个变量(通 过引用)。因为每个变量都指向同一个(共享的)数据对象,只要任何一个引用发生改变,该对 象的其它引用也会随之改变。
为了方便大家理解,最好先别考虑变量的值,而是将变量名看作对象的一个链接。
Python 提供了is 和 is not 运算符来测试两个变量是否指向同一个对象。象下面这样执行一个测试1a is b
这个表达式等价于下面的表达式1id(a) == id(b)
标准类型对象身份比较运算符:运算符功能obj1 is obj2obj1 和 obj2 是同一个对象
obj1 is not obj2obj1 和 obj2 不是同一个对象
整型和字符串缓存
在上面的例子中,您会注意到我们使用的是浮点数而不是整数。为什么这样?
整数对象和 字符串对象是不可变对象,所以Python会很高效的缓存它们。这会造成我们认为Python应该
创建新对象时,它却没有创建新对象的假象。看下面的例子:1
2
3
4
5
6
7
8
9
10
11
12
13
14>>>a = 1
>>>id(a)
8402824
>>>b = 1
>>>id(b)
8402824
>>>
>>>c = 1.0
>>>id(c)
8651220
>>>d = 1.0
>>>id(d)
8651204
在上面的例子中,a 和 b 指向了相同的整数对象,但是 c 和 d 并没有指向相同的浮点数 对象。
如果我们是纯粹主义者,我们会希望 a 与 b 能和 c 与 d 一样,因为我们本意就是为 了创建两个整数对象,而不是像 b = a 这样的结果。
Python 仅缓存简单整数,因为它认为在 Python 应用程序中这些小整数会经常被用到。
Python 缓存的整数范围是(-1, 100),不过这个范围是会改变的,所 以请不要在你的应用程序使用这个特性。Python 2.3 中决定,在预定义缓存字符串表之外的字符串,如果不再有任何引用指向它, 那这个字符串将不会被缓存。也就是说, 被缓存的字符串将不会象以前那样永生不灭,对象回 收器一样可以回收不再被使用的字符串。
标准类型内建函数
Python 提供了一些内建函数用于这些基本对象类型:cmp(), repr(), str(), type(), 和等同于 repr()函数的单反引号 (``)运算符。
标准类型内建函数:cmp(obj1, obj2):比较 obj1 和 obj2, 根据比较结果返回整数 i:1
2
3i < 0 if obj1 < obj2
i > 0 if obj1 > obj2
i == 0 if obj1 == obj2
repr(obj) 或 `obj`:返回一个对象的字符串表示
str(obj):返回对象适合可读性好的字符串表示
type(obj):到一个对象的类型,并返回相应的 type 对象
type()
在 Python2.2 以前,type() 是内建函数。不过从那时起, 它变成了一个“工厂函数”。后面部分我们会讨论工厂函数, 现在你仍然可以将type()仅仅当成一个内建函数来看。 type() 的用法如下:type(object)
type() 接受一个对象做为参数,并返回它的类型。它的返回值是一个type类型对象。1
2
3
4
5
6
7
8>>>type(4) # int type
>>>
>>>type('Hello World!') # string type
>>>
>>>type(type(4)) # type type
在上面的例子里, 我们通过内建函数 type() 得到了一个整数和一个字符串的类型;为了 确认一下类型本身也是类型, 我们对 type()的返回值再次调用 type()。
注意type()有趣的 输出, 它看上去不象一个典型的 Python 数据类型, 比如一个整数或一个字符串,一些东西被 一个大于号和一个小号包裹着。这种语法是为了告诉你它是一个对象。每个对象都可以实现一 个可打印的字符串表示。不过并不总是这样, 对那些不容易显示的对象来说, Python 会以一 个相对标准的格式表示这个对象,格式通常是这种形式:,以 这种形式显示的对象通常会提供对象类别,对象 id 或位置, 或者其它合适的信息。
cmp()
内建函数 cmp()用于比较两个对象 obj1 和 obj2,
如果 obj1 小于 obj2,则返回一个负整 数,
如果 obj1 大于 obj2 则返回一个正整数,
如果 obj1 等于 obj2, 则返回 0。
它的行为非常 类似于 C 语言的 strcmp()函数。比较是在对象之间进行的,不管是标准类型对象还是用户自定 义对象。如果是用户自定义对象,cmp()会调用该类的特殊方法__cmp__()。
下面是几个使用 cmp()内建函数的对数值和字符串对象进行比较的例子。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17>>>a, b = -4, 12
>>>cmp(a,b)
-1
>>>cmp(b,a)
1
>>>b = -4
>>>cmp(a,b)
0
>>>
>>>a, b = 'abc', 'xyz'
>>>cmp(a,b)
-23
>>>cmp(b,a)
23
>>>b = 'abc'
>>>cmp(a,b)
0
str()和repr() (及 `` 运算符)
内建函数str() 和repr() 或反引号运算符(``) 可以方便的以字符串的方式获取对象的 内容、类型、数值属性等信息。
str()函数得到的字符串可读性好, 而 repr()函数得到的字符串通常可以用来重新获得该对象,通常情况下 obj == eval(repr(obj))这个等式是成立的。
这两个函数接受一个对象做为其参数, 返回适当的字符串。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17>>>str(4.53-2j)
'(4.53-2j)'
>>>
>>>str(1)
'1'
>>>
>>>str(2e10)
'20000000000.0'
>>>
>>>str([0, 5, 9, 9])
'[0, 5, 9, 9]'
>>>
>>>repr([0, 5, 9, 9])
'[0, 5, 9, 9]'
>>>
>>>`[0, 5, 9, 9]`
'[0, 5, 9, 9]'
尽管 str(),repr()和``运算在特性和功能方面都非常相似, 事实上repr() 和 `` 做的 是完全一样的事情,它们返回的是一个对象的“官方”字符串表示, 也就是说绝大多数情况下 可以通过求值运算(使用 eval()内建函数)重新得到该对象,但 str()则有所不同。str() 致力 于生成一个对象的可读性好的字符串表示,它的返回结果通常无法用于eval()求值, 但很适 合用于 print 语句输出。需要再次提醒一下的是, 并不是所有repr()返回的字符串都能够用eval()内建函数得到原来的对象:1
2
3
4>>>eval(`type(type))`)
File "", line 1 eval(`type(type))`)
^
SyntaxError: invalid syntax
也就是说 repr()输出对 Python 比较友好, 而 str()的输出对人比较友好。事实上 Python 社区目前已经不鼓励继续使用``运算符。
type() 和isinstance()
未完,待续…