虽然已经对类有了一点点模糊概念,可是,阅读前面一讲的内容的确感到累呀,都是文字,连代码都没有。python
本讲就要简单多了,尝试走一个类的流程。git
说明:关于类的这部分,我参考了《Learning Python》一书的讲解。github
建立类的方法比较简单,以下:golang
class Person:
注意,类的名称通常用大写字母开头,这是惯例。固然,若是故意不遵循此惯例,也何尝不可,可是,会给别人阅读乃至于本身之后阅读带来麻烦。既然你们都是靠右走的,你就别非要在路中间睡觉了。web
接下来,通常都要编写构造函数,在写这个函数以前,先解释一下什么是构造函数。函数
class Person: def __init__(self, name, lang, website): self.name = name self.lang = lang self.website = website
上面的类中,首先呈现出来的是一个名为:__init__()
的函数,注意,这个函数是以两个下划线开始,而后是init,最后以两个下划线结束。这是一个函数,就跟咱们此前学习过的函数同样的函数。可是,这个函数又有点奇特,它的命名是用“__”开始和结束。学习
请看官在这里要明确一个基本概念,类就是一种对象类型,和跟前面学习过的数值、字符串、列表等等类型同样。好比这里构建的类名字叫作Person,那么就是咱们要试图创建一种对象类型,这种类型被称之为Person,就如同有一种对象类型是list同样。google
在构建Person类的时候,首先要作的就是对这种类型进行初始化,也就是要说明这种类型的基本结构,一旦这个类型的对象被调用了,第一件事情就是要运行这个类型的基本结构,也就是类Person的基本结构。就比如咱们每一个人,在头脑中都有关于“人”这样一个对象类型(对应着类),一旦遇到张三(张三是一个具体人),咱们首先运行“人”这个类的基本结构:一个鼻子两只眼,鼻子下面一张嘴。若是张三符合这个基本机构,咱们不会感到惊诧(不报错),若是张三不符合这个基本结构(好比三只眼睛),咱们就会感到惊诧(报错了)。code
因为类是咱们本身构造的,那么基本结构也是咱们本身手动构造的。在类中,基本结构是写在__init__()
这个函数里面。故这个函数称为构造函数,担负着对类进行初始化的任务。对象
仍是回到Person这个类,若是按照上面的代码,写好了,是否是__init__()
就运行起来了呢?不是!这时候尚未看到张三呢,必须看到张三才能运行。所谓看到张三,看到张三这样一个具体的实实在在的人,此动做,在python中有一个术语,叫作实例化。当类Person实例化后马上运行__init__()
函数。
#!/usr/bin/env python #coding:utf-8 class Person: def __init__(self, name, lang, website): self.name = name self.lang = lang self.website = website info = Person("qiwsir","python","qiwsir.github.io") #实例化Person print "info.name=",info.name print "info.lang=",info.lang print "info.website=",info.website #上面代码的运行结果: info.name= qiwsir info.lang= python info.website= qiwsir.github.io
在上面的代码中,创建的类Person,构造函数申明了这个类的基本结构:name,lang,website。
注意观察:info=Person("qiwsir","python","qiwsir.github.io"),这句话就是将类Person实例化了。也就是在内存中建立了一个对象,这个对象的类型是Person类型,这个Person类型是什么样子的呢?就是__init__()
所构造的那样。在实例化时,必须经过参数传入具体的数据:name="qiwsir",lang="python",website="qiwsir.github.io"。这样在内存中就存在了一个对象,这个对象的类型是Person,而后经过赋值语句,与变量info创建引用关系。请看官回忆之前已经讲述过的变量和对象的引用关系。
看官是否是有点晕乎了?类、实例,这两个概念会一直伴随着后续的学习,而且,在不少的OOP模型中,都会遇到这两个概念。为了让看官不晕乎,这里将它们进行比较(注意:比较的内容,参考了《Learning Python》一书)
也许上述比较还不足以让看官理解类和实例,不要紧,继续学习,在前进中排除疑惑。
细心的看官可能注意到了,在构造函数中,第一个参数是self,可是在实例化的时候,彷佛没有这个参数什么事儿,那么self是干什么的呢?
self是一个很神奇的参数。
在Person实例化的过程当中,数据"qiwsir","python","qiwsir.github.io"经过构造函数(__init__()
)的参数已经存入到内存中,而且这些数据以Person类型的面貌存在组成一个对象,这个对象和变量info创建的引用关系。这个过程也可说成这些数据附加到一个实例上。这样就可以以:object.attribute的形式,在程序中任何地方调用某个数据,例如上面的程序中以info.name获得"qiwsir"这个数据。这种调用方式,在类和实例中常用,点号“.”后面的称之为类或者实例的属性。
这是在程序中,而且是在类的外面。若是在类的里面,想在某个地方使用传入的数据,怎么办?
随着学习的深刻,看官会发现,在类内部,咱们会写不少不一样功能的函数,这些函数在类里面有另一个名称,曰:方法。那么,经过类的构造函数中的参数传入的这些数据也想在各个方法中被使用,就须要在类中长久保存并能随时调用这些数据。为了解决这个问题,在类中,全部传入的数据都赋给一个变量,一般这个变量的名字是self。注意,这是习惯,并且是共识,因此,看官不要另外取别的名字了。
在构造函数中的第一个参数self,就是起到了这个做用——接收实例化过程当中传入的全部数据,这些数据是经过构造函数后面的参数导入的。显然,self应该就是一个实例(准确说法是应用实例),由于它所对应的就是具体数据。
若是将上面的类增长两句,看看效果:
#!/usr/bin/env python #coding:utf-8 class Person: def __init__(self, name, lang, website): self.name = name self.lang = lang self.website = website print self #打印,看看什么结果 print type(self) #运行结果 <__main__.Person instance at 0xb74a45cc> <type 'instance'>
证明了推理。self就是一个实例(准确说是实例的引用变量)。
self这个实例跟前面说的那个info所引用的实例对象同样,也有属性。那么,接下来就规定其属性和属性对应的数据。上面代码中:self.name = name,就是规定了self实例的一个属性,这个属性的名字也叫作name,这个属性的数据等于构造函数的参数name所导入的数据。注意,self.name中的name和构造函数的参数name没有任何关系,它们两个同样,只不过是一种起巧合(常常巧合),或者说是写代码的人懒惰,不想另外取名字而已,无他。固然,若是写成self.xxxooo = name,也是能够的。
其实,从效果的角度来理解,可能更简单一些,那就是类的实例info对应着self,info经过self导入实例属性的全部数据。
固然,self的属性数据,也不必定非得是由参数传入的,也能够在构造函数中本身设定。好比:
#!/usr/bin/env python #coding:utf-8 class Person: def __init__(self, name, lang, website): self.name = name self.lang = lang self.website = website self.email = "qiwsir@gmail.com" #这个属性不是经过参数传入的 info = Person("qiwsir","python","qiwsir.github.io") print "info.name=",info.name print "info.lang=",info.lang print "info.website=",info.website print "info.email=",info.email #info经过self创建实例,并导入实例属性数据 #运行结果 info.name= qiwsir info.lang= python info.website= qiwsir.github.io info.email= qiwsir@gmail.com #打印结果
经过这个例子,其实让咱们拓展了对self的认识,也就是它不只仅是为了在类内部传递参数导入的数据,还能在构造函数中,经过self.attribute的方式,规定self实例对象的属性,这个属性也是类实例化对象的属性,即作为类经过构造函数初始化后所具备的属性。因此在实例info中,经过info.email一样可以获得该属性的数据。在这里,就能够把self形象地理解为“内外兼修”了。或者按照前面所提到的,将info和self对应起来,self主内,info主外。
其实,self的话题尚未结束,后面的方法中还会出现它。它真的神奇呀。
前面已经说过了,构造函数__init__
就是一个函数,只不过长相有点古怪罢了。那么,函数中的操做在构造函数中依然可行。好比:
def __init__(self,*args): pass
这种类型的参数:*args和前面讲述函数参数同样,就很少说了。忘了的看官,请去复习。可是,self这个参数是必须的,由于它要来创建实例对象。
不少时候,并非每次都要从外面传入数据,有时候会把构造函数的某些参数设置默认值,若是没有新的数据传入,就应用这些默认值。好比:
class Person: def __init__(self, name, lang="golang", website="www.google.com"): self.name = name self.lang = lang self.website = website self.email = "qiwsir@gmail.com" laoqi = Person("LaoQi") #导入一个数据name="LaoQi",其它默认值 info = Person("qiwsir",lang="python",website="qiwsir.github.io") #所有从新导入数据 print "laoqi.name=",laoqi.name print "info.name=",info.name print "-------" print "laoqi.lang=",laoqi.lang print "info.lang=",info.lang print "-------" print "laoqi.website=",laoqi.website print "info.website=",info.website #运行结果 laoqi.name= LaoQi info.name= qiwsir ------- laoqi.lang= golang info.lang= python ------- laoqi.website= www.google.com info.website= qiwsir.github.io
在这段代码中,看官首先要体会一下,“类是实例的工厂”这句话的含义,经过类Person生成了两个实例:laoqi、info
此外,在看函数赋值的状况,容许设置默认参数值。
至此,仅仅是初步构建了一个类的基本结构,完成了类的初始化。