跟老齐学Python之编写类之一创建实例


Posted in Python onOctober 11, 2014

说明:关于类的这部分,我参考了《Learning Python》一书的讲解。

创建类

创建类的方法比较简单,如下:

class Person:

 注意,类的名称一般用大写字母开头,这是惯例。当然,如果故意不遵循此惯例,也未尝不可,但是,会给别人阅读乃至于自己以后阅读带来麻烦。既然大家都是靠右走的,你就别非要在路中间睡觉了。

接下来,一般都要编写构造函数,在写这个函数之前,先解释一下什么是构造函数。

class Person:

    def __init__(self, name, lang, website):

        self.name = name

        self.lang = lang

        self.website = website

 上面的类中,首先呈现出来的是一个名为:__init__()的函数,注意,这个函数是以两个下划线开始,然后是init,最后以两个下划线结束。这是一个函数,就跟我们此前学习过的函数一样的函数。但是,这个函数又有点奇特,它的命名是用“__”开始和结束。

请看官在这里要明确一个基本概念,类就是一种对象类型,和跟前面学习过的数值、字符串、列表等等类型一样。比如这里构建的类名字叫做Person,那么就是我们要试图建立一种对象类型,这种类型被称之为Person,就如同有一种对象类型是list一样。

在构建Person类的时候,首先要做的就是对这种类型进行初始化,也就是要说明这种类型的基本结构,一旦这个类型的对象被调用了,第一件事情就是要运行这个类型的基本结构,也就是类Person的基本结构。就好比我们每个人,在头脑中都有关于“人”这样一个对象类型(对应着类),一旦遇到张三(张三是一个具体人),我们首先运行“人”这个类的基本结构:一个鼻子两只眼,鼻子下面一张嘴。如果张三符合这个基本机构,我们不会感到惊诧(不报错),如果张三不符合这个基本结构(比如三只眼睛),我们就会感到惊诧(报错了)。

由于类是我们自己构造的,那么基本结构也是我们自己手动构造的。在类中,基本结构是写在__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》一书)

类和实例
 •“类提供默认行为,是实例的工厂”,我觉得这句原话非常经典,一下道破了类和实例的关系。看上面代码,体会一下,是不是这个理?所谓工厂,就是可以用同一个模子做出很多具体的产品。类就是那个模子,实例就是具体的产品。所以,实例是程序处理的实际对象。
 •类是由一些语句组成,但是实例,是通过调用类生成,每次调用一个类,就得到这个类的新的实例。
 •对于类的:class Person,class是一个可执行的语句。如果执行,就得到了一个类对象,并且将这个类对象赋值给对象名(比如Person)。
 
也许上述比较还不足以让看官理解类和实例,没关系,继续学习,在前进中排除疑惑。

self的作用

细心的看官可能注意到了,在构造函数中,第一个参数是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

此外,在看函数赋值的情况,允许设置默认参数值。

至此,仅仅是初步构建了一个类的基本结构,完成了类的初始化。

Python 相关文章推荐
记录Django开发心得
Jul 16 Python
python+selenium实现163邮箱自动登陆的方法
Dec 31 Python
python用fsolve、leastsq对非线性方程组求解
Dec 15 Python
用Python获取摄像头并实时控制人脸的实现示例
Jul 11 Python
python中for循环把字符串或者字典添加到列表的方法
Jul 20 Python
python中的TCP(传输控制协议)用法实例分析
Nov 15 Python
python 实现兔子生兔子示例
Nov 21 Python
Python FtpLib模块应用操作详解
Dec 12 Python
pytorch 实现在预训练模型的 input上增减通道
Jan 06 Python
python 递归调用返回None的问题及解决方法
Mar 16 Python
Python面向对象程序设计之继承、多态原理与用法详解
Mar 23 Python
你应该知道的Python3.6、3.7、3.8新特性小结
May 12 Python
跟老齐学Python之关于类的初步认识
Oct 11 #Python
跟老齐学Python之传说中的函数编写条规
Oct 11 #Python
python类继承用法实例分析
Oct 10 #Python
python中元类用法实例
Oct 10 #Python
跟老齐学Python之总结参数的传递
Oct 10 #Python
跟老齐学Python之变量和参数
Oct 10 #Python
跟老齐学Python之重回函数
Oct 10 #Python
You might like
php操作mysql数据库的基本类代码
2014/02/25 PHP
PhpStorm terminal无法输入命令的解决方法
2016/10/09 PHP
php+redis实现多台服务器内网存储session并读取示例
2017/01/12 PHP
JavaScript的document对象和window对象详解
2010/12/30 Javascript
在多个页面使用同一个HTML片段《续》
2011/03/04 Javascript
ASP.NET jQuery 实例17 通过使用jQuery validation插件校验ListBox
2012/02/03 Javascript
js动态修改整个页面样式达到换肤效果
2014/05/23 Javascript
用js读、写、删除Cookie代码分享及详细注释说明
2014/06/05 Javascript
$(&quot;&quot;).click与onclick的区别示例介绍
2014/09/25 Javascript
javascript动画算法实例分析
2015/07/31 Javascript
JavaScript实现移动端轮播效果
2017/06/06 Javascript
Vue2.0 实现移动端图片上传功能
2018/05/30 Javascript
Vue组件全局注册实现警告框的实例详解
2018/06/11 Javascript
JS数组方法join()用法实例分析
2020/01/18 Javascript
JS XMLHttpRequest原理与使用方法深入详解
2020/04/30 Javascript
[02:14]完美“圣”典2016风云人物:xiao8专访
2016/12/01 DOTA
Python ftp上传文件
2016/02/13 Python
Python语言生成水仙花数代码示例
2017/12/18 Python
python selenium UI自动化解决验证码的4种方法
2018/01/05 Python
Python装饰器用法示例小结
2018/02/11 Python
python获取代理IP的实例分享
2018/05/07 Python
python os.listdir按文件存取时间顺序列出目录的实例
2018/10/21 Python
Python2比较当前图片跟图库哪个图片相似的方法示例
2019/09/28 Python
Python csv文件的读写操作实例详解
2019/11/19 Python
OpenCV 表盘指针自动读数的示例代码
2020/04/10 Python
TensorFlow的环境配置与安装教程详解(win10+GeForce GTX1060+CUDA 9.0+cuDNN7.3+tensorflow-gpu 1.12.0+python3.5.5)
2020/06/22 Python
python tkiner实现 一个小小的图片翻页功能的示例代码
2020/06/24 Python
使用keras框架cnn+ctc_loss识别不定长字符图片操作
2020/06/29 Python
捷克购买家具网站:JENA nábytek
2020/03/19 全球购物
软件测试笔试题
2012/10/25 面试题
幼儿园门卫岗位职责
2014/02/14 职场文书
保密工作实施方案
2014/02/24 职场文书
借名购房协议书范本
2014/10/06 职场文书
2016年校长新年寄语
2015/08/17 职场文书
Python还能这么玩之用Python做个小游戏的外挂
2021/06/04 Python
解决Jenkins集成SonarQube遇到的报错问题
2021/07/15 Java/Android