大家好,下面我说一下我对面向对象的理解,不会讲的很详细,因为有很多人的博客都把他写的很详细了,所以,我尽可能简单的通过一些代码让初学者可以理解面向对象及他的三个要素。

摘要:
1、首先介绍一下面向对象
、然后分别讲一下封装、继承和多态
、最后通过一段面向对象的案例来更好的理解一下面向对象

  

  python是一门面向对象编程语言,对面相对象语言编码的过程叫做面向对象编程。

  面向对象时一种思想,与之相对对的是面向过程。我们先简单说一下面向过程。

  面向过程其实就是把过程当做设计核心,根据问题的发展顺序,依次解决问题,尽可能的把过程中涉及到的问题完善解决。他有他的优点,当拿到一个问题时,可以方便的按执行的步骤写代码,但是当逻辑关系变得复杂时,有一个地方出现差错就会导致整个程序无从下手。

  既然主要是说python,那我们还是回来说说python的面向对象,面向对象的编程语言还是很多的,例如C++、Java等等。

  面向对象程序设计把计算机程序的执行看做一组对象的集合,每个对象之间进行消息的传送处理。有一个显著的优点就是,对某个对象进行修改,整个程序不会受到影响,自定义数据类型就是面向对象中的类的概念,而我们需要把他们的接口处理好就很好办了。说了这么多话,有些小白已经看不下去了,那接下来我们进入主题。

  • 上面说了,自定义数据类型就是面向对象中的类的概念。我们先介绍一下待会儿会用到的一些术语:
 # 我认为还是通过个例子更容易让人理解

 # 首先我们定义一个类
class A(object): # 这是一个类,class是创建一个类的标志
# 类变量(类属性):类属性是指类的属性,属性就是我们刚学编程的时候听过的变量。
x = 7
y = "asdf" def __init__(self,name,age):
self.name = name
self.age = age # 方法:方法就是在类外面我们写的函数,放在类里就叫做一个方法
def func(self):
c = 8 # 实例变量:定义在方法中的变量只作用于当前实例的类
print("Hello World!") a = A() # 创建一个对象,实例化

  上面的部分代码还需要再解释一下:

  • object:

    • 注意类名后面括号里有个参数object,他代表所有类的基类,也叫作超类。
    • 这就有了一个新式类和旧式类的概念:
    • 当用到多继承的时候,如果子类中没有想用的方法名或属性名,他会自动回到上面去找。那么按广度优先遍历的方法去寻找就是新式类(object);深度优先(括号里啥也没有)。
  • __init__():构造函数,实例化的时候若不显示的定义,那么默认调用一个无参的,是初始化的意思。

一、封装

  含义:对外面隐藏对象的属性和方法,仅提供接口。

  作用:安全性(通过私有变量改变对外的使用),复用性

 #!/usr/bin/env python
# -*- coding:utf-8 -*- class Student(object):
def __init__(self, name, score):
# 属性仅前面有两个下划线代表私有变量,外部无法访问,因此我们定义了两个新的方法,这样可以避免外部通过score乱改分数,仅当我们自己知道接口才可以修改
self.__name = name
self.__score = score def info(self):
print('name: %s ; score: %d' % (self.__name,self.__score)) def getScore(self):
return self.__score def setScore(self, score):
self.__score = score stu = Student('Tom',99)
print('修改前分数:',stu.getScore())
stu.info()
stu.setScore(59)
print('修改后分数:',stu.getScore())
stu.info()

  封装还是比较好理解的,不过其中还有一些,比如析构函数,重写等等知识点最好在官方文档过一遍。

二、继承

  2.1.1、含义

  前面我们提到过,面向对象编程有个好处就是代码复用,而其中一种方法就是通过继承机制。继承就是说定义的一个新类,继承现有的类,获得现有类的非私有属性、方法。提到个私有,就是上面提到的那个前面加两个下划线的那个东西,他在外部无法调用,继承他的子类也不能。被继承的那个类称为基类、父类或超类,子类也可以叫做派生类。

  2.1.2、特点

    1、在继承中,基类的构造方法(__init__()方法)不会被自动调用,需要在子类的构造方法中专门调用。

    2、在调用基类的方法时需要加上基类的类名前缀,并带上self参数变量。区别于在类中调用普通函数时不需要带self参数。

    3、在python中,首先查找对应类型的方法,如果在子类中找不到对应的方法,才到基类中逐个查找。

  2.2、单继承

    直接上代码,仔细理解一下里面的关系,我把讲解都写在注释的地方。

 #!/usr/bin/env python
# -*- coding:utf-8 -*- # 这是定义了一个基类
class Person(object):
def __init__(self, name, age, money):
self.name = name
self.age = age
self.__money = money # 私有属性
# 被引入时,继承不了,但他们的set,get函数可以继承 def setMoney(self,money):
self.__money = money def getMoney(self):
return self.__money def run(self):
print("run") def eat(self):
print("eat")

  下面是定义的一个子类,继承自上方的类,来使用父类中的方法和属性:

 # 由于我将每个类写在了不同的文件里,所以需要引入一下,这就和我们调用库一样
from 单继承的实现.person import Person class Student(Person):
def __init__(self,name,age,stuid,money):
# 调用父类中的__init__(),supper括号中的内容,在python3以后可以不写,写上更安全些
super(Student,self).__init__(name,age,money) # 让父类的self当做子类的对象
# 子类可以由一些自己独有的属性或者方法
self.stuid = stuid

   创建对象,通过子类使用父类的属性和方法:

 from 单继承的实现.student import Student

 stu = Student('Tom',18,111,999) # 创建Student对象
# 下列方法和属性均是在父类Person中定义的,在Student继承之后,便可以直接使用
print(stu.name, stu.age)
stu.run()
print(stu.getMoney())

  2.3、多继承

  上面的单继承要多理解一下,单继承理解了之后,多继承也就没什么了。

 #!/usr/bin/env python
# -*- coding:utf-8 -*- class Father(object):
def __init__(self,money):
self.money = money
def play(self):
print("play")
def func(self):
print("func1") class Mother(object):
def __init__(self,facevalue):
self.facevalue = facevalue
def eat(self):
print("eat")
def func(self):
print("func2") class Children(Father,Mother):
def __init__(self,money,facevalue):
# 多继承时调用父类的属性
Father.__init__(self,money)
Mother.__init__(self,facevalue) def main():
c = Children(300,100)
print(c.money,c.facevalue)
c.play()
c.eat()
# 注意:如果多个父类中有相同的方法名,默认调用括号中前面的类
c.func()
if __name__ == "__main__":
main()

三、多态

  • 多态:是指一种事物的多种形态
  • 多态性:多态性是指具有不同功能的函数可以使用相同的函数名,这样就可以用一个函数名调用不同内容的函数。在面向对象方法中一般是这样表述多态性:向不同的对象发送同一条消息,不同的对象在接收时会产生不同的行为(即方法)。也就是说,每个对象可以用自己的方式去响应共同的消息。所谓消息,就是调用函数,不同的行为就是指不同的实现,即执行不同的函数。
  • eg:在python中的“+”号,它既可以表示数字的加法,也可以表示字符串的拼接,(__add__())
 class Animal(object):
def __init__(self, name):
self.name = name def run(self):
pass def animalRun(self):
self.run() class Cat(Animal):
def run(self):
print('cat is running') class Dog(Animal):
def run(self):
print('dog is running') d = Dog('dog')
c = Cat('cat') Animal.animalRun(c)
Animal.animalRun(d)

四、面向对象案例

  下面给一个小程序,是模拟反恐精英,保卫者和敌人。主要是让大家看明白,只有简单的几个功能,希望大家可以从中理解面向对象的思想。python中,任何都是对象。

                  

  首先,这是我的几个类模块,分开来写比较清晰一点,写在一起也是没问题的。接下来我们一点一点的分析:

  。。。。。。。。。。

  得有人,好人和坏人

  。。。。。。。。。。

  人得有武器,先给他们两种:枪和手榴弹

  。。。。。。。。。。

  枪还有个弹夹也可以作为对象

  。。。。。。。。。。

  想想还有什么,差不多了吧,那么我们就开始写,想到什么再补充

 #!/usr/bin/env python
# -*- coding:utf-8 -*- from cs.person import Person class Gengster(Person): # 初始化,血量默认为100
def __init__(self, gun, grenade, blood=100):
self.gun = gun
self.grenade = grenade
self.blood = blood # 人有开枪的功能
def fire(self,person):
person.blood.amount -= 5 # 对谁开枪,那个人就要减血
self.gun.shoot() # 这个人开枪,这又调用了枪的类,关于子弹的减少在枪的类里 # 扔手榴弹,实际上是和枪一样的
def fire2(self,person):
person.blood -= 10
self.grenade.damage() # 同样通过另一个类来控制数量的减少,使代码看起来简洁点 # 给弹夹里加子弹
def fillbullet(self):
self.gun.bulletbox.bulletcount += 10 # 补血,并保证满血只能是100
def fillblood(self,num):
self.blood += num
if self.blood > 100:
self.blood = 100
print("补血后血量:" + str(self.blood))

坏蛋

 # 主要注释和上一个类似,这里不赘述

 #!/usr/bin/env python
# -*- coding:utf-8 -*- from cs.person import Person class Profector(Person): def __init__(self, gun, grenade, blood = 100):
self.gun = gun
self.grenade = grenade
self.blood = blood def fire(self, person):
person.blood -= 5
self.gun.shoot()
print(str(person) + "血量减少5,剩余" + str(person.blood) ) def fire2(self,person):
person.blood -= 10
self.grenade.damage() def fillbullet(self):
self.gun.bulletbox.bulletcount += 10 def fillblood(self,num):
self.blood += num
if self.blood > 100:
self.blood = 100
print("补血后血量:" + str(self.blood))

好人

 #!/usr/bin/env python
# -*- coding:utf-8 -*- class Gun(object): # 初始化,把弹夹放里面,通过人来控制枪,再来控制弹夹
def __init__(self,bulletbox):
self.bulletbox = bulletbox def shoot(self):
if self.bulletbox.bulletcount == 0:
print('没子弹了')
else:
self.bulletbox.bulletcount -= 1
print(str(self) + '开一枪,还剩%d颗子弹' % (self.bulletbox.bulletcount))

 # 与枪类似

 #!/usr/bin/env python
# -*- coding:utf-8 -*- class Grenade(object): def __init__(self,grenadecount):
self.grenadecount = grenadecount def damage(self):
if self.grenadecount == 0:
print('手雷没有了')
else:
self.grenadecount -= 1
print(str(self) + "轰他一炮,手雷还剩%d颗" % (self.grenadecount))

手榴弹

 #!/usr/bin/env python
# -*- coding:utf-8 -*- class Bulletbox(object): # 弹夹只需控制数量就好了
def __init__(self,bulletcount):
self.bulletcount = bulletcount

弹夹

  这下差不多了,人也有了,武器也有了,可以开展了

 #!/usr/bin/env python
# -*- coding:utf-8 -*- from cs.grenade import Grenade
from cs.gun import Gun
from cs.bulletbox import Bulletbox
from cs.gengster import Gengster
from cs.profector import Profector
# 参数:枪,手榴弹,血(默认100,且上限为100) # 创建弹夹,枪,手榴弹的对象,以备人使用
bulletbox = Bulletbox(10)
gun = Gun(bulletbox)
grenade = Grenade(20) # 创建人对象
good1 = Profector(gun,grenade)
good2 = Profector(gun,grenade)
bad1 = Gengster(gun,grenade)
bad2 = Gengster(gun,grenade) print("好人1开枪打坏人1和2")
good1.fire(bad1)
good1.fire(bad2)
print("好人2开枪打坏人1和2")
good2.fire(bad1)
good2.fire(bad2)
print("坏人1炸好人1和2")
bad1.fire2(good1)
bad1.fire2(good2)
print("坏人2炸好人1和2")
bad2.fire2(good1)
bad2.fire2(good2)
print("坏人1补血3个")
bad1.fillblood(3)

main

  现在这一套流程就结束了,刚开始看也许看不太懂,要仔细看一下每个类之间的关系,先想清楚了,再来看代码是如何实现的

  有没有看出来点区别,面向过程编程是就事论事,而面向对象,先把对象找出来,通过对象之间的关系把他们联系起来。想想如果要用面向过程来实现这个,代码会写成什么样子呢。

  然而并没有结束,记不记得前面的类中有两对是比较类似的,好人和坏人,枪和手榴弹(这个里面的类还不太一样),那么想到了什么没有,前面提到的继承的优点是什么来着,----复用。我们可以可以用继承来写一下呢,如果你说这个也没少几行代码嘛,那么,如果在实际当中你要创建成百上千的对象呢,难道还要每个都复制粘贴改代码吗,还占空间对不对。

  那么我们写一个人类,毕竟好人和坏人都是人:

 #!/usr/bin/env python
# -*- coding:utf-8 -*- class Person(object): def __init__(self, gun, grenade, blood):
self.gun = gun
self.grenade = grenade
self.blood = blood def fire(self, person):
person.blood -= 5
self.gun.shoot()
print(str(person) + "血量减少5,剩余" + str(person.blood) ) def fire2(self, person):
person.blood -= 10
self.grenade.damage()
print(str(person) + "血量减少10,剩余" + str(person.blood) ) def fillbullet(self):
self.gun.bulletbox.bulletcount += 10 def fillblood(self,num):
self.blood += num
if self.blood > 100:
self.blood = 100
print(str(self) + "补血后血量:" + str(self.blood))

person

  现在我们就不必把好人坏人都重写了,只需要继承一下人类就好了:

 #!/usr/bin/env python
# -*- coding:utf-8 -*- from cs.person import Person class Profector(Person): def __init__(self, gun, grenade, blood = 100):
super(Profector,self).__init__(gun, grenade, blood) class Gengster(Person): def __init__(self, gun, grenade, blood=100):
super(Gengster, self).__init__(gun, grenade, blood) # 这里面有个supper,他就是对父类的继承

好人和坏人

  我知道大家看的有点迷了,我把他整在一起了,不过还是建议大家先根据每个小模块学习,顺便理解一下引入自定义模块。下面是完整代码,可以直接粘贴:

 #!/usr/bin/env python
# -*- coding:utf-8 -*- class Bulletbox(object):
def __init__(self,bulletcount):
self.bulletcount = bulletcount class Gun(object):
def __init__(self,bulletbox):
self.bulletbox = bulletbox def shoot(self):
if self.bulletbox.bulletcount == 0:
print('没子弹了')
else:
self.bulletbox.bulletcount -= 1
print(str(self) + '开一枪,还剩%d颗子弹' % (self.bulletbox.bulletcount)) class Grenade(object):
def __init__(self,grenadecount):
self.grenadecount = grenadecount def damage(self):
if self.grenadecount == 0:
print('手雷没有了')
else:
self.grenadecount -= 1
print(str(self) + "轰他一炮,手雷还剩%d颗" % (self.grenadecount)) class Person(object):
def __init__(self, gun, grenade, blood):
self.gun = gun
self.grenade = grenade
self.blood = blood def fire(self, person):
person.blood -= 5
self.gun.shoot()
print(str(person) + "血量减少5,剩余" + str(person.blood) ) def fire2(self, person):
person.blood -= 10
self.grenade.damage()
print(str(person) + "血量减少10,剩余" + str(person.blood) ) def fillbullet(self):
self.gun.bulletbox.bulletcount += 10 def fillblood(self,num):
self.blood += num
if self.blood > 100:
self.blood = 100
print(str(self) + "补血后血量:" + str(self.blood)) class Profector(Person):
def __init__(self, gun, grenade, blood = 100):
super(Profector,self).__init__(gun, grenade, blood) class Gengster(Person):
def __init__(self, gun, grenade, blood=100):
super(Gengster, self).__init__(gun, grenade, blood) bulletbox = Bulletbox(10)
gun = Gun(bulletbox)
grenade = Grenade(20) good1 = Profector(gun,grenade)
good2 = Profector(gun,grenade)
bad1 = Gengster(gun,grenade)
bad2 = Gengster(gun,grenade) print("好人1开枪打坏人1和2")
good1.fire(bad1)
good1.fire(bad2)
print("好人2开枪打坏人1和2")
good2.fire(bad1)
good2.fire(bad2)
print("坏人1炸好人1和2")
bad1.fire2(good1)
bad1.fire2(good2)
print("坏人2炸好人1和2")
bad2.fire2(good1)
bad2.fire2(good2)
print("坏人1补血3个")
bad1.fillblood(3)

all

  我在这里还想和大家一起看一下结果:

  看一下有没有发现什么问题呢?

  血量减少的人的对象还是正常的,然而看一下开枪的人。有没有发现好人1和好人2的对象时同一个地址呢,他们的子弹也是累积的递减;坏人使用手榴弹也是。为什么开枪的人会是这样,而受伤的人却是正常的呢?

  提醒一下,我们前面创建的那些对象,有些是为了下一个对象调用而准备的,看看出错是在那个模块里错的,出错的和正确的他们之间有哪些不一样呢,而且出错的原理是什么呢?大家可以思考思考,评论区互相讨论一下。

  

  今天就到这里了,大家多多互动,互相学习。希望路过的大佬指点指点。

python面向对象(封装、继承、多态)+ 面向对象小栗子的更多相关文章

  1. python面向对象(封装,继承,多态)

    python面向对象(封装,继承,多态) 学习完本篇,你将会深入掌握 如何封装一个优雅的借口 python是如何实现继承 python的多态 封装 含义: 1.把对象的属性和方法结合成一个独立的单位, ...

  2. php面向对象 封装继承多态 接口、重载、抽象类、最终类总结

    1.面向对象 封装继承多态  接口.重载.抽象类.最终类 面向对象 封装继承多态  首先,在解释面向对象之前先解释下什么是面向对象? [面向对象]1.什么是类? 具有相同属性(特征)和方法(行为)的一 ...

  3. Java基础——面向对象(封装——继承——多态 )

    对象 对象: 是类的实例(实现世界中 真 实存在的一切事物 可以称为对象) 类: 类是对象的抽象描述 步骤: 1.定义一个类 (用于 描述人:) ( * 人:有特征和行为) 2.根据类 创建对象 -- ...

  4. <python基础>封装,继承,多态,重写,重载

    什么是封装? 所谓的面向对象就是将我们的程序模块化,对象化,把具体事物的特性属性和通过这些属性来实现一些动作的具体方法放到一个类里面,这就是封装.封装是我们所说的面相对象编程的特征之一.除此之外还有继 ...

  5. Python 入门 之 面向对象的三大特性(封装 / 继承 / 多态)

    Python 入门 之 面向对象的三大特性(封装 / 继承 / 多态) 1.面向对象的三大特性: (1)继承 ​ 继承是一种创建新类的方式,在Python中,新建的类可以继承一个或多个父类,父类又可以 ...

  6. java面向对象(封装-继承-多态)

    框架图 理解面向对象 面向对象是相对面向过程而言 面向对象和面向过程都是一种思想 面向过程强调的是功能行为 面向对象将功能封装进对象,强调具备了功能的对象. 面向对象是基于面向过程的. 面向对象的特点 ...

  7. 浅谈学习C++时用到的【封装继承多态】三个概念

    封装继承多态这三个概念不是C++特有的,而是所有OOP具有的特性. 由于C++语言支持这三个特性,所以学习C++时不可避免的要理解这些概念. 而在大部分C++教材中这些概念是作为铺垫,接下来就花大部分 ...

  8. Java三大特性(封装,继承,多态)

    Java中有三大特性,分别是封装继承多态,其理念十分抽象,并且是层层深入式的. 一.封装 概念:封装,即隐藏对象的属性和实现细节,仅对外公开接口,控制在程序中属性的读和修改的访问级别:将抽象得到的数据 ...

  9. OOP三大核心封装继承多态

    OOP支柱 3 个核心:封装 继承 多态 封装就是将实现细节隐藏起来,也起到了数据保护的作用. 继承就是基于已有类来创建新类可以继承基类的核心功能. 在继承中 另外一种代码重用是:包含/委托,这种重用 ...

  10. python面向对象之继承/多态/封装

    老师说,按继承/多态/封装这个顺序来讲. 子类使用父类的方法: #!/usr/bin/env python # coding:utf-8 class Vehicle: def __init__(sel ...

随机推荐

  1. 为libevent添加websocket支持(上)

    在跨平台网络基础库中,libevent与asio近年来使用比较广泛.asio对boost的依赖太大,个人认为发展前途堪忧,尤其asio对http没有很好的支持也是缺点之一. libevent对http ...

  2. Git:二、本地文件操作

    文件必须放在本地Git仓库的文件夹下,子文件夹也可以. 1.添加/修改 git add <文件名> 2.提交 git commit -m "本次提交说明" 可以add很 ...

  3. mysql学习之完整的select语句

    本文内容: 完整语法 去重选项 字段别名 数据源 where group by having order by limit 首发日期:2018-04-11 完整语法: 先给一下完整的语法,后面将逐一来 ...

  4. JAVA设计模式——代理(静态代理)

    定义 为其它的对象提供一种代理,以控制这个对象的访问 使用场景 当不想直接访问某个对象的时候,就可以通过代理 1.不想买午餐,同事帮忙带 2.买车不用去厂里,去4s店 3.去代理点买火车票,不用去车站 ...

  5. mssql sqlserver 判断字符串大小写的方法分享

    摘要:下文讲述使用sql脚本的方法判断字符串为大小写的方法分享,如下所示 实验环境:sqlserver 2008 R2 实现思路: 将字符串转换为大写或小写然后转换为二进制编码, 然后和源字符串做对比 ...

  6. Failed to decrypt protected XML node "DTS:Password" with error 0x8009000B "Key not valid for use in specified state.". You may not be authorized to access this information. This error occurs when t

    Question SSIS包从A服务器搬迁到B服务器,运行报错 Description: Failed to decrypt protected XML node "DTS:Password ...

  7. MapFileParser.sh: Permission denied

    Unity项目,需要用Xcode运行,结果报了错误. 解决方案: 1.打开终端, 2.输入以下命令: chmod +x   /Users/......./MapFileParser.sh (MapFi ...

  8. Lua table笔记

    记录我在使用lua的过程中的一些笔记 默认key为数字递增 local tb={"A",[3]="C","B"} 这个tb通过下标1,2,3 ...

  9. 排序算法之选择排序的思想以及Java实现

    1 基本思想 选择排序的思想是,每一次从待排序的数据元素中选出最小(或最大)的一个元素,存放在序列的起始位置,直到全部待排序的数据元素排完. 2,算法的实现(Java) package Algorit ...

  10. ABAP on HANA之CDS Association和Path Expression

    本文阐述了ABAP CDS association的概念,并且展示了在CDS视图中和SQL语句中写路径表达式(Path Expression)代码的方法.我也会解释如何在CDS asociation中 ...