自学计划 - python 小白基础教程 - 第十课:面向对象

目录

简介
第一课:python 的介绍
第二课:变量与操作符
第三课:字符串和数字
第四课:条件执行语句
第五课:列表与元组
第六课:循环语句
第七课:集合
第八课:字典
第九课:函数
第十课:面向对象
第十一课:文件的操作
第十二课:学生管理系统

面向对象编程

面向对象编程这个概念,刚接触过编程的同学可能都会听说过。而 python 从设计之初就已经是一门面向对象的语言,也正因为如此我们可以很方便地在 python 中使用面向对象编程的思想。

与面向对象相对的是面向过程编程,传统的 C 语言就是面向过程为主。主要是按照业务流程把梳理代码顺序执行。当业务逻辑清晰,业务规模不大的情况下当然没问题。一旦业务规模庞大,逻辑不清楚,增加需求的时候,开发难度就会曾几何数递增。

面向对象开发中会把对应的事物都抽象成对象的概念,这样子我们在增加对应业务时只需要增加相应的对象类,而无需改变其他类就能达到我们的目的。

面向对象的三大基本特征是:封装继承多态。随着这篇文章的深入我们会一一深入学习这三个基本特征。

类与对象

在面向过程的编程方式中,如果我们要定义一些人名与欢迎语,并用方法执行,我们通常会写出以下代码。

xiaoming = {'name': '小明', 'hello': '你好'}
kelly = {'name': 'Kelly', 'hello': 'hello'}

def say_hello(human):
    print('{}:{}'.format(human['name'], human['hello']))

say_hello(xiaoming)
say_hello(kelly)
小明:你好呀
Kelly:hello

在人物数量不多时,代码结构还是很清晰的,可是一旦人物数量变多了,就是一个灾难。

xiaoming = {'name': '小明', 'hello': '你好'}
kelly = {'name': 'Kelly', 'hello': 'hello'}
xiaoli = {'name': '小李', 'hello': '雷猴啊'}
lotus = {'name': 'Lotus', 'helo': 'bonjour'}

def say_hello(human):
    print('{}:{}'.format(human['name'], human['hello']))

say_hello(xiaoming)
say_hello(kelly)
say_hello(xiaoli)
say_hello(lotus)
小明:你好
Kelly:hello
小李:雷猴啊
Traceback (most recent call last):
  File ".\first.py", line 14, in <module>
    say_hello(lotus)
  File ".\first.py", line 8, in say_hello
    print('{}:{}'.format(human['name'], human['hello']))
KeyError: 'hello'

大量的重复代码已经是个灾难,一不小心写错一个字母还引起了程序的崩溃。此时如果再加上 say_bye等几个方法,代码结构将会更加混乱不堪。

接着我们用面向对象的思维来改造我们的代码,类的定义一定程度上就对应着基本特征封装

class Human:
    # 定义了一个类

    def __init__(self, name, hello):
        # 构造函数
        self.name = name
        self.hello = hello

    def say_hello(self):
        # 类的方法
        print('{}:{}'.format(self.name, self.hello))

# 实例化我们的对象
xiaoming = Human('小明', '你好呀')
kelly = Human('Kelly', 'hello')
xiaoli = Human('小李', '雷猴啊')
lotus = Human('Lotus', 'bonjour')


xiaoming.say_hello()
kelly.say_hello()
xiaoli.say_hello()
lotus.say_hello()
小明:你好呀
Kelly:hello
小李:雷猴啊
Lotus:bonjour

(Class)是用来描述具有相同属性(Attribute)和方法(Method)对象的集合。对象(Object)是(Class)的具体实例。

此时的 Human 就是我们定义的类,从面向对象编程来说就相当于封装了一个类。然后通过Human这个类创造了两个对象 xiaomingkelly

python 中我们通过 class 来定义一个类,指定了类应当有的属性与方法。将相关的属性(Attribute)与方法(Method)封装到对象中,是来源于现实世界的一个设计思想。因为现实世界中的任何物体都有其对应的属性(组成部分)与方法(功能作用)。

比如一个手机,它有屏幕、处理器、摄像头等等属性,有打电话、玩游戏、看电影等等方法。一个人,有姓名、身高、学历等等属性,有交流、工作、学习等等方法。

回到我们的代码,__init__ 是一个构造函数,它要求在实例化的时候传入 namehello 两个参数,并将其保存为自身的属性。这里的 self 代表着一个自身的实例对象。

xiaoming = Human('小明', '你好呀') 意味着实例化了一个 Human 对象。接着我们调用 xiaoming.say_hello() 便完成了对其对象方法的调用。

私有属性与私有方法 Private attribute and private method

一个生活中的人,你自然不会在脑门上看到他的名字,与说你好的方式。这些信息只会在你们初次交流时才可以得到。那我们就可以将 namehello 包括 say_hello 设置为私有属性与私有方法。而只对外面暴露一个 contact 方法。

class Human:
    # 定义了一个类

    def __init__(self, name, hello):
        # 构造函数
        self.__name = name
        self.__hello = hello

    def __say_hello(self):
        # 类的方法
        print('{}:{}'.format(self.__name, self.__hello))

# 实例化我们的对象
xiaoming = Human('小明', '你好呀')
xiaoming.__say_hello() # 这行代码会报错
Traceback (most recent call last):
  File ".\first.py", line 16, in <module>
    xiaoming.__say_hello()  # 这行代码会报错
AttributeError: 'Human' object has no attribute '__say_hello'

python 中通过在属性名与方法名前加上 __ 双下划线来定义私有成员,此时的私有成员便不再能从类外访问。我们可以再对其增加一个 contact 方法供外部调用。

class Human:
    # 定义了一个类

    def __init__(self, name, hello):
        # 构造函数
        self.__name = name
        self.__hello = hello

    def __say_hello(self):
        # 类的方法
        print('{}:{}'.format(self.__name, self.__hello))

    def contact(self):
        self.__say_hello()

# 实例化我们的对象
xiaoming = Human('小明', '你好呀')
xiaoming.contact()
小明:你好呀

以上体现了封装的理念,只对外暴露需要的接口,而对不必要的信息进行隐藏。

类的继承

通过继承,我们可以重用父类的属性与方法。

class Human:
    def __init__(self, name, hello):
        self.__name = name
        self.__hello = hello

    def __say_hello(self):
        print('{}:{}'.format(self.__name, self.__hello))

    def contact(self):
        self.__say_hello()

class Programmer(Human):
    def code(self):
        print('我正在快乐地编程')

class Fireman(Human):
    def outfire(self):
        print('我正在跟火灾作斗争')

xiaoming = Programmer('小明', '你好呀')
xiaoli = Fireman('小李', '雷猴啊')

xiaoming.contact()
xiaoming.code()

xiaoli.contact()
xiaoli.outfire()
小明:你好呀
我正在快乐地编程
小李:雷猴啊
我正在跟火灾作斗争

此时我们便已经定义了两个子类 ProgrammerFireman 都继承自 Human 类,既重用了父辈的方法与属性,又各自新增了自己独有的方法。

多态

通过多态,我们可以在不同的子类对同一个方法实现不同功能。

class Human:
    # 定义了一个类

    def __init__(self, name, hello):
        # 构造函数
        self.__name = name
        self.__hello = hello

    def __say_hello(self):
        # 类的方法
        print('{}:{}'.format(self.__name, self.__hello))

    def contact(self):
        self.__say_hello()

    def work():
        raise NotImplementedError()

class Programmer(Human):
    def contact(self):
        super().contact() # 调用父类的方法
        print('我是一个快乐的程序员')

    def work(self):
        print('我正在快乐地编程')

class Fireman(Human):
    def contact(self):
        super().contact() # 调用父类的方法
        print('我是一个消防员,遇火灾联系我!')

    def work(self):
        print('我正在跟火灾作斗争')

xiaoming = Programmer('小明', '你好呀')
xiaoli = Fireman('小李', '雷猴啊')

xiaoming.contact()
xiaoming.work()

xiaoli.contact()
xiaoli.work()
小明:你好呀
我是一个快乐的程序员
我正在快乐地编程
小李:雷猴啊
我是一个消防员,遇火灾联系我!
我正在跟火灾作斗争

我们重写了其中的 contact 方法。通过 super() 获取到了父类并调用了其 contact 方法。

我们同样在父类中定义了 work 方法,raise NotImplementedError() 的意思是在调用 work 方法前必须对其进行重写,不然会报错。 于是我们在子类中根据 Programmer 类与 Fireman 类的特性,分别对 work 方法进行了重写。

这时多态的效果便已达到,针对同样继承的父类,不同的子类在同一方法上进行了不同的实现

带来的好处是显而易见的,针对所有继承自 Human 类的子类,我们都可以直接调用他的 work 方法让他去工作,而无需关心内部的实现。

练习

1.定义一个女(男)朋友类,类至少包含姓名国籍 两个属性, 问好约会两个方法。并将其实例化。

开放式问题,答案不唯一。

解析

  1. 定义一个女(男)朋友类,类至少包含姓名国籍 两个属性, 问好约会两个方法。并将其实例化。

开放式问题,答案不唯一。

class Friend:
    def __init__(self, name, country):
        self.name = name
        self.country = country

    def say_hello(self):
        print('%s向你问好' % self.name)

    def date(self):
        print('约会吗?我在%s等你' % self.country)

xiaofang = Friend(name='小芳', country='日本')
xiaoming = Friend(name='小明', country='美国')

xiaofang.say_hello()
xiaofang.date()

xiaoming.say_hello()
xiaoming.date()
小芳向你问好
约会吗?我在日本等你
小明向你问好
约会吗?我在美国等你
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,456评论 5 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,370评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,337评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,583评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,596评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,572评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,936评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,595评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,850评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,601评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,685评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,371评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,951评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,934评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,167评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,636评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,411评论 2 342

推荐阅读更多精彩内容