python 对象

转载:http://www.cnblogs.com/wilber2013/p/4628443.html

http://www.cnblogs.com/wilber2013/p/4634209.html


Python是一门面向对象的语言,在Python中一切都是对象,函数是对象,类型也是对象。

下面就看看Python中对象相关的内容。

Python对象基本概念

Python对象有三个基本的要素:

  • 身份:对象的唯一性身份标志,是该对象的内存地址(可用内建函数id()获得)
  • 类型:对象的类型决定了该对象可以保存什么类型的值,可进行什么样的操作(可用内建函数type()获得)
  • 值:对象代表的数据

下面看看以下代码:

复制代码
num =7

print id(num)
print type(num)
print num
print dir(num)

print 

def isEven(num):
    return (num%2 and [False] or [True])[0]
    
print id(isEven)
print type(isEven)
print isEven
print dir(isEven)
复制代码

 通过代码中可以看到,我们定义了一个int类型的数值对象,以及一个函数对象,通过内建的dir()函数,我们可以查看对象支持的属性/方法:

Python对象起源

在Python中有两个最基本的对象,<type 'object'> 和 <type 'type'>,这两个对象是所有对象的起源。

通过下面的代码看看<type 'object'> 和 <type 'type'>的关系:

代码中使用了"__class__"属性来查看对象的类型,以及"__bases__"属性来查看对象的父类,这两个属性很重要,可以查看本对象跟其他对象的关系。

根据上面代码的输出可以得到下面的对象关系图:

在Python对象系统中,<type 'object'>和<type 'type'>的关系就像鸡和蛋的关系,不能说谁先于(创建)谁,两者是相互依赖的,共同构成了Python对象系统的基础。

  • <type 'type'>的类型是<type 'type'>(它本身),<type 'type'>的父类是<type 'object'>
  • <type 'object'>的类型是<type 'type'>,<type 'object'>没有父类

介绍到这里是不是感觉有点绕,没关系,我们继续看看下面关于对象的分类。

Python对象的分类

在Python中,所有的对象可以分成两类:Type Object(类型对象,没错,类型也是一个对象)和Non-type Object(非类型对象)。

下面通过一个具体的例子来看看对象的分类:

根据上面例子的输出可以得到下面的对象关系图:

这里我们就以list、mylist为例进行分析:

  1. 首先,list是一种Python内置的容器类型,也就是说list是一个类型对象
  2. 根据"__class__"属性可以看到,list这个类型对象的类型是<type 'type'>
  3. 根据"__bases__"属性可以看到,list这个类型对象的父类是<type 'object'>
  4. 通过mylist的"__class__"属性(<type 'list'>)可以看到,mylist是list类型对象生成的一个对象(Non-type Object(非类型对象))

通过上面的分析我们可以验证Python对象分类的原则:

  • 如果一个对象是<type 'type'>的实例, 那它就是Type Object(类型对象), 否则是Non-type Object(非类型对象)

Type Object和Non-type Object

通过前面的分析可以看到,Type Object(类型对象)包括:

  • <type 'type'>
  • <type 'object'>
  • 通过<type 'type'>生成的对象(类型对象)

Type Object(类型对象)有两个重要的特性:

  • 可以被子类化(subclassed)
  • 可以被实例化(instantiated)

回到上面的对象图,Type Object(类型对象)就是存放在前两个方格中的对象。

那么其余的对象就是Non-type Object(非类型对象),回到对象图,Non-type Object(非类型对象)就是存放在第三个方格中的对象。实线不能出现在第三个方格中,因为这里的对象都不能进行子类化(继承);同样,虚线箭头不能出现在第三个方格中,因为这里的对象都不能进行实例化。

再看<type 'type'>

<type 'type'>本身是一个类型对象;同时,<type 'type'>是所有类型对象(包括<type 'type'>自身)的类型,也就是说,对所有的类型对象进行type()或者获取"__class__"属性都将得到<type 'type'>。

我们可以导入types模块,然后通过dir()内建函数来查看所有的内置类型对象,这些类型对象的类型都是<type 'type'>:

再看<type 'object'>

同样,<type 'object'>是一个类型对象(因为type(object)是<type 'type'>);同时,<type 'object'>是所有类型对象(除去<type 'object'>本身)的父类

type()和__class__

这里需要提一下的是,type()这个内置函数以及"__class__"这个属性,这两种方式都可以得到对象的类型,一般来说两种方式得到的结果是相同的。

但是,对于Python中的经典类(classic class),type()和"__class__"的结果就是不同的了(这里就不介绍classic class和new-style class了):

对于new-style class,type()和"__class__"的结果就是相同的了。

总结

本文介绍了Python对象中的一些基本点:

  • Python对象的三要素
  • Python对象中的两个基本对象<type 'type'>和<type 'object'>
  • Python对象的分类:Type Object(类型对象)和Non-type Object(非类型对象)

Python对象的比较

Python对象有三个要素:身份,类型和值,所以我们就分别从这三个角度出发看看对象之间的比较。

对象身份比较

对象身份的比较,其实就是比较对象的内存地址,即内建函数id()的结果比较。可以用来判断不同的变量是否指向了同一个地址。

直接看例子:

通过例子的输出可以得到,f1和f2指向了不同的对象(地址);但是,i1和i2却指向了相同的对象(地址)。

之所以产生这种差异,是因为Python对整数对象和字符串对象会进行缓存,所以没有产生新的对象,而是指向了缓存的对象。不同版本的Python处理缓存是不一样的,所以同样的例子可能产生不同的结果。

对于对象身份比较,还可以使用Python中的"is"关键字:

复制代码
obj1 is obj2
# 等价
id(obj1) == id(obj2)

obj1 is not obj2
# 等价
id(obj1) != id(obj2)
复制代码

对象类型比较

通过type()内建函数,可以得到一个对象的类型,然后就可以进行类型比较了。

看一段代码:

例子中使用了三种方式进行对象类型的比较:

  • 直接将type(obj)与类型进行比较
  • 将type(obj)的身份跟类型的身份进行比较
  • 通过内建的isinstance()函数,判断一个对象是不是有特定类型实例化得到的
    • 其第一个参数为对象,第二个为类型名或类型名的一个列表
    • 其返回值为布尔型

简单看看前两种方式的区别,第一种方式是直接将两个类型对象的值进行比较;而第二种方式比较的是两个类型对象的身份,这种方式的原理是,如果两个类型对象的身份不同,那么两个类型对象的值肯定不同。

对象值比较

对于Python对象,可以直接使用比较操作符(>,<,==等)进行对象值的比较。关于Python的内建对象,有一套比较规则,比如两个list对象的比较就是按照list比较规则进行的。

这里我们就主要看看自定义类型的对象之间的比较。

自定义类型的对象值比较

在Python中,所有的类型都有一套用于比较的"魔术方法" ,对于自定义的类型,我们就可以通过实现这些方法来定义自定义类型的对象的比较行为:

  • __cmp__(self, other) : __cmp__ is the most basic of the comparison magic methods. __cmp__ should return a negative integer if self < other, zero if self == other, and positive if self > other.
  • __eq__(self, other) Defines behavior for the equality operator, ==.
  • __ne__(self, other) Defines behavior for the inequality operator, !=.
  • __lt__(self, other) Defines behavior for the less-than operator, <.
  • __gt__(self, other) Defines behavior for the greater-than operator, >.
  • __le__(self, other) Defines behavior for the less-than-or-equal-to operator, <=.
  • __ge__(self, other) Defines behavior for the greater-than-or-equal-to operator, >=.

看一个例子,我们定义了一个"语句"类型,并实现了一些比较方法,这样对于改类型的对象,我们就可以直接通过比较操作符进行对象值比较了。

有一点需要注意的是,关于自定义类型的对象,如果没有实现比较操作符对应的"魔术方法",那么将默认使用对象身份(id())进行比较。

"is"和"=="的差别

这里需要注意一下"is"和"=="之间的差别:

  • "is"用来比较对象的身份是否相等,也就是说,比较对象的内存地址是否相同(变量是否指向同一个对象)
  • "=="用来比较对象的内容(值)是否相等

看下面的代码:

对于变量c和d,由于数值超过了Python对整型数的缓存范围,所有d就会是Python生成的一个新的对象。因此,c和d的值是相同的,但是身份却是不同的。

可变对象和不可变对象

在Python中,一切都是对象,Python中不存在所谓的传值,一切传递的都是对象的引用(也可以认为是传址)。

上一篇文章中了解到,根据Python对象的类型,可以将Python对象分为:Type Object(类型对象)和Non-type Object(非类型对象)。

同样,根据对象的可变性,也可以将Python对象分为两类:可变(mutable)对象和不可变(immutable)对象。

  • 不可变(immutable)对象:对象的内容不可变,当尝试改变对象内容的时候,会创建一个新的对象;也就是说对象的身份(id())会发生变化
    • 例如:number、string,tuple
  • 可变(mutable)对象:对象的内容可变,当改变对象内容的时候,对象的身份(id())不会变化
    • 例如:list、dict、set

看一段简单的代码:

tuple是"可变的"

虽然元组对象本身是不可变的,但这并不意味着元组包含的可变对象也不可变。

看下面的例子:

现在我们根据下图分析这段代码,tpl这个元组的第四个元素比较特殊,是一个list;所以,在tpl中第四个元素存放的是这个list的地址(身份id(),引用)。

元组的不可变性就决定了tpl第四个元素对应的内容,即list的地址不能改变了,但是,这个地址37865712指向的内容是可以被改变的。

总结

本篇介绍了Python对象的比较,包括对象的身份,类型以及值的比较。对于自定义类型的对象,如果需要进行比较操作,可以通过自定义比较操作相关的"魔术方法"。

另外,文中简单介绍了Python对象的可变性,对比了可变(mutable)对象和不可变(immutable)对象之间的不同。





  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值