0.说明
说对象是面向对象编程语言最重要的一部分一点也不为过,没有了“对象”,面向对象将无从谈起。Python也是如此,如果无法掌握对象,你很难有大的进步与提升。
1.Python对象
(1)对象特性
Python使用对象模型来存储数据,构造任何类型的值都是一个对象,所有的Python对象都拥有下面的三个特性:
-
身份:每个对象一唯一身份标识,可使用内建函数id()查看该值(可以认为这个值是该对象的内在地址)
-
类型:对象的类型决定了对象(可以保存什么类型的值,进行什么样的操作,遵循什么样的规则),可以使用内建函数type()查看(对象的类型也是一个对象,因此type()返回的是一个对象,而不是字符串)
-
值:对象表示的数据项
对于身份特性,它是可读的;对于类型特性,新式类型和类可以修改,但不建议初学者这样做,另外Python有一系列的基本(内建)数据类型,可以自己定义(一般推荐通过创建和实例化类来对特定的数据进行存储);对于值,取决于该对象是否支持更新操作。
(2)对象属性
Python使用句点标记法来访问属性,最常用的属性是函数和方法,当然一些Python对象也有数据属性。
2.标准类型
-
数字(分为几个子类型,有三个是整型)
Integer 整型
Boolean 布尔型
Long integer 长整型
Floating point real number 浮点型
Complex number 复数型
-
String 字符串
-
List 列表
-
Tuple 元组
-
Dictionary 字典
需要注意的是,使用上面这些基本类型所构造的值都为该类型对应的对象。
3.其他内建类型
-
类型
-
Null对象(None)
-
文件
-
集合/固定集合
-
函数/方法
-
模块
-
类
下面主要说明Type和None类型,其它的后面会讨论。
(1)类型对象和type类型对象
前面提到,对象有一系列行为和特性,而这些信息就是保存在对象的类型当中:
>>> type(42)
<type 'int'>
type()返回的是一个类型对象,表明42是一个数字类型对象,而<type ‘int’>本身也有所属于的类型,可以继续使用type()来查看:
>>> type(type(42))
<type 'type'>
<type ‘type’>表示<type ‘int’>是一个type类型对象,尝试继续使用内建函数type()来作进一步操作:
>>> type(type(type(42)))
<type 'type'>
得到的还是type类型对象,于是可以有下面的结论:
-
所有类型对象的类型都是type,它也是所有Python类型的根和所有Python标准类的默认元类(metaclass)
-
在Python中,类就是类型,实例是对应类型的对象(类比42的例子,42属于数字类型,它是数字类型构造值后的一个数字对象,或者说42是类int的一个实例对象,因为现在类型就是类)
(2)None:Python的Null对象
Python有一个特殊的类型,被称为Null对象或者NoneType,它只有一个值,那就是None
>>> None
>>> type(None)
<type 'NoneType'>
None没有什么有用的属性,它的布尔值总是False。
(3)布尔值
前面提及布尔值,有以下几点注意:
-
每个对象天生具有布尔True或False值
-
空对象 值为零的任何数字或者Null对象的布尔值都是False
-
用户创建的类实例如果定义了nonzero(__nonzero__())或length(__len__())且值为0,那么它们的布尔值就是False
4.内部类型
-
代码
-
帧
-
跟踪记录
-
切片
-
省略
-
Xrange
(1)代码对象
代码对象是编译过的Python源代码片段,它是可执行对象,通过调用内建函数compile()可以得到,然后可以被exec命令或eval()内建函数来执行。
代码对象本身不包含任何执行环境信息,它是用户自定义函数的核心,在被执行时动态获得上下文(事实上代码对象是函数的一个属性)。一个函数除了有代码对象属性以外,还有一些其他函数必须的属性,包括函数名 文档字符串 默认参数及全局命名空间等。
(2)帧对象
帧对象表示Python的执行栈帧。帧对象包含Python解释器在运行时所需要知道的所有信息,它的属性包含下面这些信息:
-
指向上一帧的链接
-
正在被执行的代码对象
-
本地及全局名称空间字典及当前指令等
每次函数调用产生一个新的帧,每一个帧对象都会相应创建一个C栈帧,用到帧对象的一个地方是跟踪记录对象。
(3)跟踪记录对象
当异常发生时,一个包含针对异常的栈跟踪信息的跟踪记录对象被创建。如果一个异常有自己的处理程序,处理程序就可以访问这个跟踪记录对象。
(4)切片对象
当使用Python扩展的切片语法时,就会创建切片对象。
(5)省略对象
省略对象用于扩展切片语法中,起记号作用。这个对象在切片语法中表示省略号。类似Null对象None,省略对象有一个唯一的名字Ellipsis:
>>> Ellipsis
Ellipsis
>>> type(Ellipsis)
<type 'ellipsis'>
它的布尔值始终为True。
(6)Xrange对象
调用内建函数xrange()会生成一个Xrange对象,xrange()是内建函数range()的兄弟版本,用于需要节省内存使用或range()无法完成的超大数据集场合。
5.标准类型操作符
(1)对象值的比较
比较操作符用来判断同类型对象的值是否相等,所有的内建类型(前面所说的标准类型和其他内建类型)均支持比较运算,比较运算结果返回布尔值True或False。
注意:比较操作是针对对象的值进行的,就就是说比较的是对象的数值而不是对象本身。
另外提及Python的一个特性,多个操作可以在同一行上进行,求值顺序为从左到右:
>>> 3 < 4 < 7
True
等价于:
>>> 3 < 4 and 4 < 7
True
(2)对象身份比较
在Python中,应该将变量名看成是对象的一个链接,对对象的一个引用,它被指向这个对象,而不是直接赋值为该对象。可以使用内建函数id()或关键字is和is not来比较两个对象身份:
-
相同值,指向相同对象
>>> foo1 = foo2 = 4.3
>>> a is b
True
>>> id(a) == id(b)
True
-
值相同,指向不同对象
>>> foo1 = 4.3
>>> foo2 = 1.3 + 3.0
>>> foo1 is foo2
False
>>> id(foo1)
18024120
>>> id(foo2)
18024048
在Python中,有一个’仅缓存简单整型‘的概念,即对于一些简单的不可变对象,比如整型对象和字符串对象,Python会先将它们缓存到内存中,当需要就直接被引用,而无需创建,可以看下面的例子:
>>> a = 1
>>> id(a)
17953112
>>> b = 1
>>> id(b)
17953112
>>> c = 1.0
>>> id(c)
18024096
>>> d = 1.0
>>> id(d)
18024072
当然,只是缓存简单整型:
>>> e = 336
>>> id(e)
18554008
>>> f = 336
>>> id(f)
18601504
理解起来相对是比较简单的了。
(3)布尔类型
按优先级从高到低,主要是:
-
not
-
and
-
or
6.标准类型内建函数
即用于操作基本肉类的内建函数,如下:
-
cmp(obj1, obj2):大于返回负数,小于返回正数,等于返回0
-
repr(obj)或`obj`:返回一个对象的字符串表示
-
str(obj):返回对象适合可读性好的字符串表示
-
type(obj):得到一个对象的类型,并返回相应的类型对象(type对象,与type类型对象不同)
(1)type()
接受一个对象作为参数,并返回它的类型,它的返回值是一个类型对象:
>>> type(4)
<type 'int'>
>>> type('Hello World!')
<type 'str'>
>>> type(type(4))
<type 'type'>
以<>语法表示的,说明其是一个对象,每个对象都可以实现一个可打印的字符串表示。但对于那些不容易显示的对象来说,Python会以一个相对标准的格式来表示这个对象,如:<object_something_or_another>,其中提供了对象类别 对象id或位置等信息。
(2)cmp()
例子如下:
>>> 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()或“用来以字符串方式获取对象的内容 类型和数值等信息,作如下说明:
-
str()
str()函数得到的字符串表示可读性比较好,适合用于print输出,大多数情况下都无法将该字符串表示通过eval()求值来得到原来的对象(当然,简单的就除外了)。
>>> str(1)
'1'
>>> eval(str(1))
1
>>> str([1, 2, 3])
'[1, 2, 3]'
>>> eval(str([1, 2, 3]))
[1, 2, 3]
-
repr()或“
返回一个对象的“官方”字符串表示,也就是说大多数情况下,都可以将字符串通过eval()求值来得到原来的对象(当然,也有例外的情况)。
>>> 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()
-
type()
type()用于返回一个对象的类型,它的返回值是一个类型对象,这些前面已经有所提及,再给出下面的例子:
>>> class Foo: pass
...
>>> class foo(object): pass
...
>>> type(Foo)
<type 'classobj'>
>>> type(foo)
<type 'type'>
type(foo)的输出之所以会这样,是因为类就是类型。
-
isinstance()
如果需要判断一个对象的类型,可以使用下面的方法:
>>> from types import IntType
>>> type(42) == IntType
True
当使用isinstance()时,就会方便很多:
>>> 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.标准类型的分类
标准类型:基本内建数据对象原始类型,解释如下:
-
基本:是因为这些类型都是Python提供的标准呀核心类型
-
内建:是因为这些类型是Python默认就提供的
-
数据:是因为他们用于一般数据存储
-
对象:是因为对象是数据和功能的默认抽象
-
原始:是因为这些类型提供的是最底层的粒度数据存储
-
类型:是因为他们就是数据类型
当然,我们可以对标准类型进行分类,以便于我们更好地理解这些标准类型的特性。
(1)存储模型
分类标准:看这种类型的对象能保存多少个对象。于是会有下面两种情况:
-
原子/标量存储:能保存单个字面对象的类型
-
容器存储:可容纳多个对象的类型
分类如下:
存储模型 | |
分类 | Python类型 |
标量/原子类型 | 数值(所有的数值类型),字符串(全部是文字) |
容器类型 | 列表 元组 字典 |
其中对于容器对象(也就是列表等这些类型的一个实例对象了),它们都能容纳不同类型的对象。另外需要注意的是字符串,因为在Python中并没有“字符”类型的数据结构,所以字符串是一个自我包含的文字类型。
(2)更新模型
分类标准:值是否可改变。于是会有下面两种情况:
-
可变类型:对象的值可以被更新
-
不可变类型:对象的值不可以被更改
分类如下:
更新模型 | |
分类 | Python类型 |
可变类型 | 列表 字典 |
不可变类型 | 数字 字符串 元组 |
数字或字符串是不可变类型,也许难以理解,但可以看下面的例子:
>>> a = 3
>>> id(a)
17953064
>>> a = 6
>>> id(a)
17952992
>>> x = 'abc'
>>> id(x)
140407360100672
>>> x = 'change'
>>> id(x)
140407359514784
也就是说,表面上值是改变了,但实际上是3这个数字对象被丢弃回收,然后创建了一个新的数字对象6。而对于字符串类型,这也充分说明了在Python中是没有字符类型这一数据结构的。
但对于可变类型,情况就不一样了:
>>> 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还是在其他的面向对象编程语言中,都是十分重要的,如果无法掌握对象,那么也就不能充分利用面向对象编程语言的特性。
发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/109123.html原文链接:https://javaforall.cn
【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛
【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...