面向对象

浏览 910

课文

## 面向对象编程 面向对象编程这个概念,刚接触过编程的同学可能都会听说过。而 python 从设计之初就已经是一门面向对象的语言,也正因为如此我们可以很方便地在 python 中使用面向对象编程的思想。 与面向对象相对的是面向过程编程,传统的 C 语言就是面向过程为主。主要是按照业务流程把梳理代码顺序执行。当业务逻辑清晰,业务规模不大的情况下当然没问题。一旦业务规模庞大,逻辑不清楚,增加需求的时候,开发难度就会曾几何数递增。 面向对象开发中会把对应的事物都抽象成对象的概念,这样子我们在增加对应业务时只需要增加相应的对象类,而无需改变其他类就能达到我们的目的。 面向对象的三大基本特征是:`封装`、`继承`、`多态`。随着这篇文章的深入我们会一一深入学习这三个基本特征。 ## 类与对象 在面向过程的编程方式中,如果我们要定义一些人名与欢迎语,并用方法执行,我们通常会写出以下代码。 ```python xiaoming = {'name': '小明', 'hello': '你好'} kelly = {'name': 'Kelly', 'hello': 'hello'} def say_hello(human): print('{}:{}'.format(human['name'], human['hello'])) say_hello(xiaoming) say_hello(kelly) ``` ```output 小明:你好呀 Kelly:hello ``` 在人物数量不多时,代码结构还是很清晰的,可是一旦人物数量变多了,就是一个灾难。 ```python 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) ``` ```output 小明:你好 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`等几个方法,代码结构将会更加混乱不堪。 接着我们用面向对象的思维来改造我们的代码,类的定义一定程度上就对应着基本特征`封装`。 ```python 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() ``` ```output 小明:你好呀 Kelly:hello 小李:雷猴啊 Lotus:bonjour ``` `类`(Class)是用来描述具有相同`属性`(Attribute)和`方法`(Method)对象的集合。`对象`(Object)是`类`(Class)的具体实例。 此时的 `Human` 就是我们定义的类,从面向对象编程来说就相当于封装了一个类。然后通过`Human`这个类创造了两个对象 `xiaoming` 与 `kelly`。 在 `python` 中我们通过 `class` 来定义一个类,指定了类应当有的属性与方法。将相关的`属性`(Attribute)与`方法`(Method)封装到对象中,是来源于现实世界的一个设计思想。因为现实世界中的任何物体都有其对应的`属性`(组成部分)与`方法`(功能作用)。 比如一个手机,它有屏幕、处理器、摄像头等等属性,有打电话、玩游戏、看电影等等方法。一个人,有姓名、身高、学历等等属性,有交流、工作、学习等等方法。 回到我们的代码,`__init__` 是一个构造函数,它要求在实例化的时候传入 `name` 与 `hello` 两个参数,并将其保存为自身的属性。这里的 `self` 代表着一个自身的实例对象。 `xiaoming = Human('小明', '你好呀')` 意味着实例化了一个 `Human` 对象。接着我们调用 `xiaoming.say_hello()` 便完成了对其对象方法的调用。 ## 私有属性与私有方法 _Private attribute and private method_ 一个生活中的人,你自然不会在脑门上看到他的名字,与说你好的方式。这些信息只会在你们初次交流时才可以得到。那我们就可以将 `name`、`hello` 包括 `say_hello` 设置为私有属性与私有方法。而只对外面暴露一个 `contact` 方法。 ```python 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() # 这行代码会报错 ``` ```output 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` 方法供外部调用。 ```python 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() ``` ```output 小明:你好呀 ``` 以上体现了封装的理念,只对外暴露需要的接口,而对不必要的信息进行隐藏。 ## 类的继承 `通过继承,我们可以重用父类的属性与方法。` ```python 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() ``` ```output 小明:你好呀 我正在快乐地编程 小李:雷猴啊 我正在跟火灾作斗争 ``` 此时我们便已经定义了两个子类 `Programmer` 与 `Fireman` 都继承自 `Human` 类,既重用了父辈的方法与属性,又各自新增了自己独有的方法。 ## 多态 `通过多态,我们可以在不同的子类对同一个方法实现不同功能。` ```python 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() ``` ```output 小明:你好呀 我是一个快乐的程序员 我正在快乐地编程 小李:雷猴啊 我是一个消防员,遇火灾联系我! 我正在跟火灾作斗争 ``` 我们重写了其中的 `contact` 方法。通过 `super()` 获取到了父类并调用了其 `contact` 方法。 我们同样在父类中定义了 `work` 方法,`raise NotImplementedError()` 的意思是在调用 `work` 方法前必须对其进行重写,不然会报错。 于是我们在子类中根据 `Programmer` 类与 `Fireman` 类的特性,分别对 `work` 方法进行了重写。 这时`多态`的效果便已达到,针对同样继承的父类,不同的子类在`同一方法`上进行了`不同的实现`。 带来的好处是显而易见的,针对所有继承自 `Human` 类的子类,我们都可以直接调用他的 `work` 方法让他去工作,而无需关心内部的实现。

实战

1.定义一个女(男)朋友类,类至少包含`姓名`、`国籍` 两个属性, `问好`、`约会`两个方法。并将其实例化。 _开放式问题,答案不唯一。_

解析

1. 定义一个女(男)朋友类,类至少包含`姓名`、`国籍` 两个属性, `问好`、`约会`两个方法。并将其实例化。 _开放式问题,答案不唯一。_ ```python 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() ``` ```output 小芳向你问好 约会吗?我在日本等你 小明向你问好 约会吗?我在美国等你 ```
点击查看

评论

登录参与讨论

暂无评论

共 0 条
  • 1
前往
  • 1