跟老齐学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翻译软件实现代码(使用google api完成)
Nov 26 Python
python进阶教程之动态类型详解
Aug 30 Python
python进程管理工具supervisor使用实例
Sep 17 Python
Python实现字典的key和values的交换
Aug 04 Python
Python标准库之itertools库的使用方法
Sep 07 Python
Python简单计算给定某一年的某一天是星期几示例
Jun 27 Python
Python从Excel中读取日期一列的方法
Nov 28 Python
局域网内python socket实现windows与linux间的消息传送
Apr 19 Python
PyQt5根据控件Id获取控件对象的方法
Jun 25 Python
Python 实现Numpy中找出array中最大值所对应的行和列
Nov 26 Python
Python实现一个简单的毕业生信息管理系统的示例代码
Jun 08 Python
Python 虚拟环境工作原理解析
Dec 24 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
在PWS上安装PHP4.0正式版
2006/10/09 PHP
php简单实现查询数据库返回json数据
2015/04/16 PHP
微信开发之php表单微信中自动提交两次问题解决办法
2017/01/08 PHP
PHP实现非阻塞模式的方法分析
2018/07/26 PHP
gearman中worker常驻后台,导致MySQL server has gone away的解决方法
2020/02/27 PHP
jquery 全局AJAX事件使用代码
2010/11/05 Javascript
jquery动态加载js三种方法实例
2013/08/03 Javascript
javascript等号运算符使用详解
2015/04/16 Javascript
详解探索 vuex 2.0 以及使用 vuejs 2.0 + vuex 2.0 构建记事本应用
2017/06/16 Javascript
JavaScript实现省市联动过程中bug的解决方法
2017/12/04 Javascript
完美解决axios跨域请求出错的问题
2018/02/05 Javascript
npm scripts 使用指南详解
2018/10/08 Javascript
vue.js自定义组件directives的实例代码
2018/11/09 Javascript
微信小程序下拉刷新PullDownRefresh的使用方法
2018/11/29 Javascript
超详细动手搭建一个VuePress 站点及开启PWA与自动部署的方法
2019/01/27 Javascript
解决layui表格内文本超出隐藏的问题
2019/09/12 Javascript
使用Element的InfiniteScroll 无限滚动组件报错的解决
2020/07/27 Javascript
[01:29:46]DOTA2上海特级锦标赛C组资格赛#1 OG VS LGD第二局
2016/02/27 DOTA
python高并发异步服务器核心库forkcore使用方法
2013/11/26 Python
Python函数式编程指南(四):生成器详解
2015/06/24 Python
Python算法应用实战之队列详解
2017/02/04 Python
Python模拟用户登录验证
2017/09/11 Python
numpy.std() 计算矩阵标准差的方法
2018/07/11 Python
Python 如何创建一个简单的REST接口
2020/07/30 Python
Python爬虫爬取微信朋友圈
2020/08/06 Python
html5+css3进度条倒计时动画特效代码【推荐】
2016/03/08 HTML / CSS
Peter Alexander新西兰站:澳大利亚领先的睡衣设计师品牌
2016/12/10 全球购物
Harrods英国:世界领先的奢侈品百货商店
2020/09/23 全球购物
我们没有写servlet的构造方法,那么容器是怎么创建servlet的实例呢
2013/04/24 面试题
汉语专业应届生求职信
2013/10/01 职场文书
党员违纪检讨书
2014/02/18 职场文书
红领巾广播站广播稿(3篇)
2014/09/20 职场文书
英文感谢信范文
2015/01/21 职场文书
清明节文明祭祀倡议书
2015/04/28 职场文书
合作协议书格式范本
2016/03/21 职场文书
年会邀请函的格式及范文五篇
2019/11/02 职场文书