这篇博客主要描述Python的新风格对象(new-style objects),以下:html
New-style代表这篇博客所说的内容只适用于版本为2.2及以上的python。python
最主要,是理解type和object的区别与联系。咱们平时用的最多的是Object,好比你定义一个类时,会继承object:python3.x
>>> class Test(object): ... pass
这里你定义了一个自定义类Test
,不难看出,Test
继承了object
,也就是说,object
是Test
的超类(或者说基类)。
接下来,你能够再定义一个类:ssh
>>> class subTest(Test): ... pass
subTest
继承了Test
,同时,由于Test
继承了object
,因此也能够说subTest
继承了object
。在这里涉及到一个重要的知识点,那就是继承具备传递性。若是你仔细观察,你会发现另一个知识点,那就是:object
是全部类的超类(这句话相当重要)。那type是什么呢?它是object的类型(也就是说object是type的实例),同时,object又是type的超类。函数
“type是object的类型,同时,object又是type的超类”这句话看起来就充满疑点:那究竟是先有object仍是先有type呢?其实,“先有object和仍是type问题”就像“先有鸡仍是先有蛋问题”。到底先有谁呢?不急,请继续看:学习
你要明白这些,先要知道,python是面向对象的语言。在python里面,一切皆为对象。测试
一切皆为对象?这里对于一部分人来讲,可能不是很容易理解。这么说吧,在python里,
int
整形是对象,整数2
也是对象,你定义的函数啊,类啊都是对象,你定义的变量也是对象。总之,你在python里能用到的均可以称之为对象。ui
好了,把python里一切皆为对象给整明白后,你要明白在面向对象的体系中,存在两种关系:spa
用实线表示父子关系,是由于父与子的关系更加“贴实”。好比有人叫你列出有关蛇的词,你可能会说蛇是爬行动物
,但你不会说出蛇是Squasher
....
我想若是把上面的两种关系用代码表示出来你会更加直观:翻译
>>> class reptile(object): ... feature = "有标志本身是爬行动物的特征" ... name = "爬行动物" ... >>> class snake(reptile): ... snake_feature = "除了有标志本身是爬行动物特征,还有本身是蛇的特征" ... name = "蛇" ... >>> Squasher = snake()
class reptile(object)
和class snake(reptile)
就是表明父子关系。object是reptile的基类,reptile是snake的超类(基类)。这里有没有想起来 object
是全部类的超类?
Squasher = snake()
是类型实例关系。将类snake实例化就获得了Squasher。
这时候,有两条颇有用的规则:
实例
,“A是B的子类” --> B是一个(父)类
。B是实例,同时又是一个类?怎么回事?看完这篇博客,你会知道答案的。在这里,我来解释一下为何叫"虚线向上规则",经过观察上图右边,咱们能够清晰地见到一个带箭头的虚线,从X端出发,射向A端,此时,A端为箭头端,虚线表明类型实例关系,因此A端是类型,即X是A的实例
(换句话说,A是X的类型),经过命令X.__class__
咱们可查看X的类型。再看,一条带箭头的实线从A端射向B端,B端是箭头端,实线表明父子关系,因此B端是父类,即A是B的子类
。这时候,咱们经过将X端射向A端的虚线,向上抬,射向B端(你应该能够看到上图右上方有一条标志为implied[这个单词意思是隐藏]的向上虚线),就实现了表述X也是是B的实例
的目的。也名副其实,虚线向上嘛。虚线向下规则也能够这样推出来,我就不演示了。
总的来讲,面向对象体系里,有两种关系,一种是父子关系,经过父类与子类来描述,另外一种是类型实例关系,经过类和实例来描述。而两条规则,是将类之间,类与实例之间的关系联系在一块儿。
到这里,能够进入主题了。
上面咱们说了面向对象,那么对象(object)是什么呢?对象是python的重要核心之一:它是某个实体的抽象描述。对象拥有下面的特征:
objectname.attributename
的方式操做属性;int
;若是你想知道一个对象在内存中的位置,你能够调用id(对象)
来查看。在这里,我再次强调,在python中,一切都有对象的概念。数字2是对象,类型int
也是对象...
type
和Bases
(若是它们存在)很是重要,由于它们定义了一个对象和另外一个对象之间的关系。请记住,type
和Bases
自己也是对象,稍后会提到。
你也许会认为,对象有名字,但名字并非对象的组成部分。对象的名字存在于这个对象的命名空间(namespace)以外或者是另外一个对象的属性。也就是说:名字和这个对象不是存储在同一个“地方”
例子:测试一个整数对象
>>> two = 2 #==>(1) >>> type(two) #==>(2) <class 'int'> >>> type(type(two)) #==>(3) <class 'type'> >>> type(two).__bases__ #==>(4) (<class 'object'>,) >>> dir(two) #==>(5) ['__abs__', '__add__', '__and__', '__bool__', '__ceil__', '__class__', '__delattr__', '__dir__', '__divmod__', '__doc__', '__eq__', '__float__', '__floor__', '__floordiv__', '__format__', '__ge__', '__getattribute__', '__getnewargs__', '__gt__', '__hash__', '__index__', '__init__', '__init_subclass__', '__int__', '__invert__', '__le__', '__lshift__', '__lt__', '__mod__', '__mul__', '__ne__', '__neg__', '__new__', '__or__', '__pos__', '__pow__', '__radd__', '__rand__', '__rdivmod__', '__reduce__', '__reduce_ex__', '__repr__', '__rfloordiv__', '__rlshift__', '__rmod__', '__rmul__', '__ror__', '__round__', '__rpow__', '__rrshift__', '__rshift__', '__rsub__', '__rtruediv__', '__rxor__', '__setattr__', '__sizeof__', '__str__', '__sub__', '__subclasshook__', '__truediv__', '__trunc__', '__xor__', 'bit_length', 'conjugate', 'denominator', 'from_bytes', 'imag', 'numerator', 'real', 'to_bytes']
(1):咱们在当前命名空间给数字2分配一个名字。并将2和“two”绑定在起。
(2):这个对象的类型是<class 'int'>
。你会在其它地方见到相似<type 'int'>
,int
这样的输出,其实它们都是一个意思。
(3):额,<class 'int'>
的类型是<class 'type'>
.
(4):输出“类int
”的基类。
(5):列出整型这个对象全部的属性。
可能会以为有点乱,我稍微总结一下:数字2是类型int
(通常来说,在python中“类”和“类型”是同一种东西)的一个实例。倒过来讲,int
是数字2的类型。元组(<class 'object'>,)
是类型int
的超类(或说父类)。一个类型的超类可能不止一个,因此用元组表示。
如今,咱们引出第一条规则:
一切皆为对象
上面说的数字2,类型int,int的超类<class 'object'>
都是对象。除此以外,你定义的函数,方法...都是对象。
如今咱们来创建python的对象系统。从一块干净的画板开始...,画板分为三部分,从左到右,分别表明类的类,类,类的实例。
咱们会在这个画板中开启咱们的学习之旅...
咱们谈及对象时,用两种关系来链接各类对象,使得对象之间产生联系:
在文章开头已经详细讨论过这两种关系了。
咱们测试两个对象:object
和type
:
例子1:
>>> object #===>(1) <class 'object'> >>> type #===>(2) <class 'type'> >>> type(object) #===>(3) <class 'type'> >>> object.__class__ #===>(4) <class 'type'> >>> object.__bases__ #===>(5) () >>> type.__class__ #===>(6) <class 'type'> >>> type.__bases__ #===>(7) (<class 'object'>,)
(1),(2):python中的两个源对象的名字。咱们先前说过type()
是用来获对象的类型的。事实上,它既是一个对象,也是获取其它对象的类型的方法。
(3),(4):查看object的类型。看到object是type的实例,咱们另外也用.__class__
来核实它和type()
的输出是同样的。
(5):object没有超类,由于它自己就是全部对象的超类。
(6),(7):分别输出type的类型和超类。即,object是type的超类。type的类型是它本身
咱们把例子1获取的信息描述在画板上:
object和type是python中的两个源对象,当咱们尝试介绍它们是就会陷入“先有鸡仍是现有蛋”难题,到底先介绍谁?事实上,它们是互相依赖对方来定义,因此它们不能分开而论。
继续咱们的python实验:
>>> isinstance(object,object) #===>(1) True >>> isinstance(type, object) #===>(2) True
(1):发生了什么?其实这里利用了虚线向上规则,type是object的子类,type的实例天然也是object的实例。object是type的实例啊。
(2):这里我参考的英文文档解释是:同时应用虚线向上和虚线向下规则。但我看得一脸懵逼。由于我觉的这里和(1)同样啊:type是object的子类,type的实例天然也是object的实例。type也是type的实例啊。
若是你认为上面的解释很混乱,不用理会它。不影响你理解这篇文章的主要目的。
type
和object
都属于type objects
。type objects翻译过来就是类型对象了。类型对象的特征:
User
会表明系统中全部的用户。int
会表明系统中全部整形数字。type
。type
你没有看错。在新版本的python中类
和类型
已是同同样东西了。由一个很明显的地方就能够看出来。__class__
和type()
的输出是同样的。
在旧版本的python中,类
是特指用class语句创造出来的东西。而内置类型例如int
通常不会被认为是类
,而是被认为是类型。但在新版本中它们是同同样东西了。我以为有必要为这个改变定义一条规则:
类是类型,类型也是类(Class is Type is Class)
在>=2.3版本的python中,类和类型是同同样东西。
The term type is equivalent to the term class in all version of Python >= 2.3.
类型和非类型(或者说类和非类)都是对象,但只有类型可以被继承。非类型拥有具体的值,因此被继承是毫无心义的,并且它也不能被继承。作简单的例子,就是类型int
和它的实例2。int
是类型,2是非类型。你说说,继承2有什么意义?
是否仍是会疑惑到底社么是类型?什么是非类型?
这里有一条判断规则送给你:
若是一个对象,它的类型是“<class 'type'>”,那么,它是类型,不然不是。
还记得怎么判断一个对象的类型吗?没错的,__class__和type()随意你用。
小总结:
注意咱们在画板中只画出两个对象的直接关系,隐藏的关系就不画了,节省咱们的精力和画板尺寸。
python这条船上可不止只有两个源对象。经过这两个源对象能够繁育出一堆对象:
Figure 2.2. 一些内置对象
上图中的一些内置类型,下面经过例子来测试:
>>> list #====>(1) <class 'list'> >>> list.__class__ #====>(2) <class 'type'> >>> list.__bases__ #====>(3) (<class 'object'>,) >>> tuple.__class__,tuple.__bases__ #====>(4) (<class 'type'>, (<class 'object'>,)) >>> dict.__class__,dict.__bases__ #和(4)同样原理 (<class 'type'>, (<class 'object'>,)) >>> mylist = [1,2,3] #====>(5) >>> mylist.__class__ #====>(6) <class 'list'> >>> mylist.__bases__ #====>(7) Traceback (most recent call last): File "<stdin>", line 1, in <module> AttributeError: 'list' object has no attribute '__bases__'
(1):内置对象list;
(2):list的类型是<class 'type'>;
(3):list的超类是(<class 'object'>,);
(4):内置对象tuple.tuple的类型和超类分别是:<class 'type'>, (<class 'object'>,);
(5)list的一个实例mylist;
(6)实例mylist的类型是<class 'list'>;
(7)实例没有超类。
咱们能够创造一个tuple或dict的实例,但咱们不能创造一个mylist的实例。由于mylist不是一个类型,它仅仅是一个实例。
内置类型是python自己就有的。那么咱们如何创造一个新的类型呢?
新的类型不可以凭空产生,它必须依赖已经存在的类型,因而,继承就呼之欲出了。
例子:经过继承产生新对象
# 在 Python 2.x,你得显式写出自定义的类继承于object: class C(object): #====>(1) pass # In Python 3.x,不用显式写出object,若是你不写,则自动继承于object: class C: #====>(2) pass class D(object): pass class E(C, D): #====>(3) pass class MyList(list): #====>(4) pass
(1):class语句告诉python解释器要经过一个存在的类型创造一个新的类型;
(2):在python3.x能够省略掉(object)。
(3):多重继承;
(4):大多数内置类型能够被继承,但不是全部的均可以。
Example 2.5.
obj = object() #====>(1) cobj = C() #====>(2) mylist = [1,2,3] #====>(3)
(1),(2):利用类型名()
的方式创造一个类型的实例。()
中可能带参数;
(3):这是python利用内置类型创造实例的语法。没什么好说的。
注意:仅仅经过对<class 'object'>
进行子类化,类型C
就自动成为<class 'type'>
的实例。缘由在常见疑问的第二个问题中。
在以上的操做后,本来空白的画板能够画满了:
到这里你头脑中可能会有不少疑惑,下面列出其中一些问题以及答案,请酌情欣赏。有没有提到的请留言,我会努力搜索答案来解答:
Q: Python如何真正建立一个新对象?
A: 在python中,创造的新对象有两种:类型和非类型。类型可被继承和实例化。非类型本事就是一个实例。当python创造新对象时,它会用本身自己的类型做为新对象的类型。通常会用到两个方法__new__()
和__init__()
。因此。每一个对象都有类型。
Q:实例化的时候要指定类型,可是当继承时python如何知道用哪一个类型?
它查看你继承的超类,而且使用超类的类型来做为新对象的类型。
在大多数的状况下,<class 'object'>
的子类(和<class 'object'>
的子类的子类等等)的类型都是<class 'type'>
>>> class A(object): ... pass ... >>> class B(A): ... pass ... >>> class C(B): ... pass ... >>> A.__class__, B.__class__, C.__class__ (<class 'type'>, <class 'type'>, <class 'type'>)
Q:我可以创造一个新的类型?
A:能,这就得元类出场了,经过属性__metaclass__
你能够从新创造一个类型出来。这里我简单列一个例子。元类的话下面会简单介绍。
>>> class A(type): ... pass ... >>> class B(object, metaclass=A): ... pass ... >>> class C(B): ... pass ... >>> A.__class__, B.__class__, C.__class__ (<class 'type'>, <class '__main__.A'>, <class '__main__.A'>)
经过继承type,咱们创造出新的类型<class '__main__.A'>
。
Q:wow!那我可使用任何的类型做为metaclass的参数吗?
A:不能。只有继承了type的类可以作为metaclass的参数。
Q:我应该使用metaclass吗?
不建议使用。高手除外。
咱们最后获得一幅由不一样对象组成的地图:
在大多数状况之下,咱们都是学习第二列和第三列的内容。至于第一列,那是元类的领域了。不是全部人都要深刻学习。
来解释一下上图的东西:
类型
,第三列包含非类型
;<class 'type'>
和<type 'type'>
也是同样的。注意:<class 'type'>是全部类型的类型。<class 'object'>也是全部对象的超类(除了它本身)。
这些内容是对前面的总结:
经过实例化产生的新对象多是类型对象,也多是非类型对象。你看下图,虚线就表示实例化,第一列和第二列实例化产生的新对象就是类型对象。第三列实例化产生的新对象就是非类型对象。实例化是经过调用操做符()
来实现的。好比你自定义了一个类myclass
,实例化就是在myclass
后增长()
操做符完成的。也就是instance_of_myclass=myclass()
。
指定的超类的类型
来决定新对象的类型
。issubclass(A,B)
返回true
当且仅当:
isinstance(A,B)
返回true当且仅当:
这篇文章很长。由于水平限制,可能会出现错误。请批判性阅读。仍是建议阅读英文原文 (英语原文失效了,若是你能上世界互联网,请自行搜索,关键词:python types and objects)
版权:保留全部权,转载注明出处。