理解面向对象,首先理解要它的基础概念:python
面向对象 ( Object Oriented ) 是将现实问题构建关系,而后抽象成 类 ( class ),给类定义属性和方法后,再将类实例化成 实例 ( instance ) ,经过访问实例的属性和调用方法来进行使用。编程
在不一样的语言中,对象的定义范围不一样。在 Python 中“类”和“类的实例”都称为 对象 ( Object ),由于 Python 的类是更顶级的 type 实例化后的对象,也就是常说的“Python 里万物皆对象”;而在 Java 等静态语言中,通常把类的实例称为对象。微信
理解了理论知识后,接着经过例子,再理解面向对象的三大特征:封装、继承、多态。dom
下边咱们把“女娲造人”这个神话故事,用 Python 的面向对象代码来叙述一遍:学习
假设咱们是女娲(程序设计者),咱们忽然有个想法,想造一群和本身差很少的小人,小人须要有男女两种性别,外观和行为也有一些差别。那首先咱们分析出,无论什么性别,都应该有四肢,因此咱们先仿照本身的构造,在脑海中构思泥人的样子(抽象成基类),而后先赋予泥人一些共有的行为(定义类的实例方法):spa
class Human(object):
def __init__(self, name):
# 有个名字,有两只手,两条腿
self._name = name
self.hands = 2
self.legs = 2
def introduce_self(self):
# 介绍本身
print('我是%s' % self._name)
def work(self):
# 工做,但尚未定义具体的行为
raise NotImplementedError
复制代码
而后咱们先捏3个泥人(实例化对象),并给他们取了不一样的名字(初始化实例属性):设计
>>> a = Human('大强子')
>>> b = Human('二狗子')
>>> c = Human('三愣子')
复制代码
咱们让其中一我的介绍本身(调用实例方法):3d
>>> a.introduce_self()
我是大强子
复制代码
这里解释一下 Human
的代码,虽然设定了每一个人都要工做,但如何工做须要到具体到不一样类型的人,因此在基类里咱们并无定义 work
方法的内容,若是强行调用会抛出异常。code
还有一点,上面定义属性时,咱们把 self._name
前边加了下划线,是由于 Python 里用下划线来约定这是一个受保护变量(对应 Java 中的 protected
),咱们不但愿外界能直接访问 name
这个属性,必需要经过对象调用 introduce_self()
这个行为介绍了本身,别人才能知道他叫什么名字,这个过程就称之为封装。cdn
而后咱们继续完成想法,须要给泥人增长两种性别,而且异性之间能结婚,咱们开始在刚才泥人模型的基础上(继承于基类),构思出两种性别的泥人的区别(设置不一样的属性),而后让他们均可以工做,但工做的内容不同(调用相同的方法出现不一样结果,是多态性),并决定让男人能够娶女人(将这个行为定义为男人的方法)。
import random
class Female(Human):
def __init__(self, name):
# 调用父类的初始化方法,依然有名字、两只手、两条腿
super().__init__(name)
# 头发和力量进行随机取值
self.hair = random.randint(3, 5)
self.power = random.randint(1, 3)
# 是否已婚
self.married = False
def work():
print('%s采摘了一些果子' % self.name)
class Male(Human):
def __init__(self, name):
super().__init__(name)
self.hair = random.randint(0, 2)
self.power = random.randint(2, 5)
self.married = False
def work():
print('%s出去打猎了一天' % self.name)
def marry(self, other):
# 判断本身或对方是否已结婚,不然抛出异常
if self.married is True or other.married is True:
raise ValueError('法律不支持屡次结婚')
# 判断对方是不是女性,不然抛出异常
if isinstance(other, Female):
self.married = True
other.married = True
else:
raise TypeError('法律不支持同性结婚')
复制代码
而后咱们就可让小人活动起来:
>>> a = Male('大强子')
>>> b = Male('二狗子')
>>> c = Female('翠花')
>>> for h in [a, b, c]:
... # 调用父类的方法
... h.introduce_self()
我是大强子
我是二狗子
我是翠花
>>> for h in [a, b, c]:
... # 多态性使相同的方法产生不一样的结果
... h.work()
大强子出去打猎了一天
二狗子出去打猎了一天
翠花采摘了一些果子
>>> a.marry(c)
>>> a.married
True
>>> c.married
True
>>> b.marry(c)
ValueError: 法律不支持屡次结婚
>>> b.marry(a)
TypeError: 法律不支持同性结婚
复制代码
设计到此结束,咱们来复盘一下整个过程。
咱们先是把人的共有特征抽象成 Human
基类,这个基类并不用于实例化,而是用于让 Female
和 Male
继承它,并实现不一样的行为。这样咱们就避免把一些共有的行为重复在多个类里定义,若是咱们后续想对人类的行为进行变更,也只须要修改 Human
,继承 Human
的子类会自动得到新行为,这是 继承带来的好处。
咱们把 name
设计为受保护变量,外界没法直接访问这个属性,让每一个人的隐私获得了保障(一些没必要要的行为变得可控),这是 封装 带来的好处。
同时咱们在 Human
中预留了 work
方法,并在 Female
和 Male
都实现了不一样的效果,而后咱们知道人人都有 work
方法,所以能够像 introduce_self
同样,用循环批量调用 work
方法,这是 多态 带来的好处。
看到这里你应该有些理解:面向对象是将客观事物和一些关系,抽象成具体的模型(类),并为其设计属性和方法,即 对象 = 属性(特征)+ 方法(行为)。
若是是拥有复杂关系的需求,咱们就应该尽量将互相有关联的行为抽象成类,好比每个网页,网页中每个组件 等等。实际上面向对象帮助咱们在几万行代码的大型项目中,仍然能够游刃有余,正由于如此,才能发展为目前应用最为普遍的编程思想。
但也并非说任什么时候候都要“面向对象”,过分的封装和抽象,也会形成代码可读性的降低,以及运行效率的降低,所以咱们应该在能将事物抽象化的需求中使用面向对象。
最后,不论是面向什么编程,终究仍是要面向人生
欢迎关注微信公众号:面向人生编程,本号长期分享经验向文章
回复【资料】获取本人精选的学习视频及代码