跟老齐学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 相关文章推荐
Python中使用Beautiful Soup库的超详细教程
Apr 30 Python
python使用SMTP发送qq或sina邮件
Oct 21 Python
Python实现的朴素贝叶斯分类器示例
Jan 06 Python
Python实现的txt文件去重功能示例
Jul 07 Python
Python字符串的一些操作方法总结
Jun 10 Python
python简单区块链模拟详解
Jul 03 Python
Python 实现数据结构-循环队列的操作方法
Jul 17 Python
详解PyTorch手写数字识别(MNIST数据集)
Aug 16 Python
基于python修改srt字幕的时间轴
Feb 03 Python
python MultipartEncoder传输zip文件实例
Apr 07 Python
Python常用类型转换实现代码实例
Jul 28 Python
pytorch损失反向传播后梯度为none的问题
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常用代码大全(新手入门必备)
2010/06/29 PHP
php ci框架中加载css和js文件失败的解决方法
2014/03/03 PHP
php输入数据统一类实例
2015/02/23 PHP
js 代码优化点滴记录
2012/02/19 Javascript
基于jquery的点击链接插入链接内容的代码
2012/07/31 Javascript
jQuery实现可拖动的浮动层完整代码
2013/05/27 Javascript
jquery和ajax的关系详细介绍
2013/11/29 Javascript
javascript中HTMLDOM操作详解
2014/12/11 Javascript
BootStrap table表格插件自适应固定表头(超好用)
2016/08/24 Javascript
借助node实战JSONP跨域实例
2017/03/30 Javascript
jQuery中hover方法搭配css的hover选择器,实现选中元素突出显示方法
2017/05/08 jQuery
十个免费的web前端开发工具详细整理
2017/09/18 Javascript
记录一篇关于redux-saga的基本使用过程
2018/08/18 Javascript
微信小程序使用wxParse解析html的方法示例
2019/01/17 Javascript
Vue中通过Vue.extend动态创建实例的方法
2019/08/13 Javascript
JS localStorage存储对象,sessionStorage存储数组对象操作示例
2020/02/15 Javascript
vue中使用router全局守卫实现页面拦截的示例
2020/10/23 Javascript
vuex Module将 store 分割成模块的操作
2020/12/07 Vue.js
python+requests+unittest API接口测试实例(详解)
2017/06/10 Python
基于Python中单例模式的几种实现方式及优化详解
2018/01/09 Python
python tensorflow学习之识别单张图片的实现的示例
2018/02/09 Python
在dataframe两列日期相减并且得到具体的月数实例
2018/07/03 Python
python实现对指定字符串补足固定长度倍数截断输出的方法
2018/11/15 Python
opencv3/C++ 平面对象识别&amp;透视变换方式
2019/12/11 Python
pytorch 实现打印模型的参数值
2019/12/30 Python
python设置环境变量的作用整理
2020/02/17 Python
python用WxPython库实现无边框窗体和透明窗体实现方法详解
2020/02/21 Python
python爬虫搭配起Bilibili唧唧的流程分析
2020/12/01 Python
HTML5 FileReader对象的具体使用方法
2020/05/22 HTML / CSS
amazeui时间组件的实现示例
2020/08/18 HTML / CSS
一家专门经营包包的英国网站:MyBag
2019/09/08 全球购物
2015年公司行政后勤工作总结
2015/05/20 职场文书
2015年校务公开工作总结
2015/05/26 职场文书
实践论读书笔记
2015/06/29 职场文书
先进个人事迹材料(2016推荐版)
2016/03/01 职场文书
golang 实现时间戳和时间的转化
2021/05/07 Golang