前言:

python面向对象的三大特性:继承,封装,多态。

1. 封装: 把很多数据封装到⼀个对象中. 把固定功能的代码封装到⼀个代码块, 函数, 对象, 打包成模块. 这都属于封装的思想. 具体的情况具体分析. 比如. 你写了⼀个很⽜B的函数. 那这个也可以被称为封装. 在⾯向对象思想中. 是把⼀些看似⽆关紧要的内容组合到⼀起统⼀进⾏存储和使⽤. 这就是封装.

2. 继承: ⼦类可以⾃动拥有⽗类中除了私有属性外的其他所有内容. 说⽩了, ⼉⼦可以随便⽤爹的东⻄. 但是朋友们, ⼀定要认清楚⼀个事情. 必须先有爹, 后有⼉⼦. 顺序不能乱, 在python中实现继承非常简单. 在声明类的时候, 在类名后⾯添加⼀个⼩括号,就可以完成继承关系. 那么什么情况可以使⽤继承呢? 单纯的从代码层⾯上来看. 两个类具有相同的功能或者特征的时候. 可以采⽤继承的形式. 提取⼀个⽗类, 这个⽗类中编写着两个类相同的部分. 然后两个类分别取继承这个类就可以了. 这样写的好处是我们可以避免写很多重复的功能和代码. 如果从语义中去分析的话. 会简单很多. 如果语境中出现了x是⼀种y. 这时, y是⼀种泛化的概念. x比y更加具体. 那这时x就是y的⼦类. 比如. 猫是⼀种动物. 猫继承动物. 动物能动. 猫也能动. 这时猫在创建的时候就有了动物的"动"这个属性. 再比如, ⽩骨精是⼀个妖怪. 妖怪天⽣就有⼀个比较不好的功能叫"吃⼈", ⽩骨精⼀出⽣就知道如何"吃⼈". 此时 ⽩骨精继承妖精.

3. 多态: 同⼀个对象, 多种形态. 这个在python中其实是很不容易说明⽩的. 因为我们⼀直在⽤. 只是没有具体的说. 比如. 我们创建⼀个变量a = 10 , 我们知道此时a是整数类型. 但是我们可以通过程序让a = "alex", 这时, a⼜变成了字符串类型. 这是我们都知道的. 但是, 我要告诉你的是. 这个就是多态性. 同⼀个变量a可以是多种形态。

一  封装

封装,顾名思义就是将内容封装到某个地方,以后再去调用被封装在某处的内容。

所以,在使用面向对象的封装特性时,需要:

  • 将内容封装到某处
  • 从某处调用被封装的内容

第一步:将内容封装到某处

self 是一个形式参数,当执行 obj1 = Foo('wupeiqi', 18 ) 时,self 等于 obj1

当执行 obj2 = Foo('alex', 78 ) 时,self 等于 obj2

所以,内容其实被封装到了对象 obj1 和 obj2 中,每个对象中都有 name 和 age 属性,在内存里类似于下图来保存。

第二步:从某处调用被封装的内容

调用被封装的内容时,有两种情况:

  • 通过对象直接调用
  • 通过self间接调用

1、通过对象直接调用被封装的内容

上图展示了对象 obj1 和 obj2 在内存中保存的方式,根据保存格式可以如此调用被封装的内容:对象.属性名

1
2
3
4
5
6
7
8
9
10
11
12
13
class Foo:
    def __init__(self, name, age):
        self.name = name
        self.age = age
obj1 = Foo('wupeiqi'18)
print obj1.name    # 直接调用obj1对象的name属性
print obj1.age     # 直接调用obj1对象的age属性
obj2 = Foo('alex'73)
print obj2.name    # 直接调用obj2对象的name属性
print obj2.age     # 直接调用obj2对象的age属性

2、通过self间接调用被封装的内容

执行类中的方法时,需要通过self间接调用被封装的内容

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class Foo:
  
    def __init__(self, name, age):
        self.name = name
        self.age = age
  
    def detail(self):
        print self.name
        print self.age
  
obj1 = Foo('wupeiqi'18)
obj1.detail()  # Python默认会将obj1传给self参数,即:obj1.detail(obj1),所以,此时方法内部的 self = obj1,即:self.name 是 wupeiqi ;self.age 是 18
  
obj2 = Foo('alex'73)
obj2.detail()  # Python默认会将obj2传给self参数,即:obj1.detail(obj2),所以,此时方法内部的 self = obj2,即:self.name 是 alex ; self.age 是 78

综上所述,对于面向对象的封装来说,其实就是使用构造方法将内容封装到 对象 中,然后通过对象直接或者self间接获取被封装的内容。

二 多态

多态,同一个对象,多种形态。python默认支持多态。

# 在java或者c#定义变量或者给函数传值必须定义数据类型,否则就报错。def func(int a):print('a必须是数字')# 而类似于python这种弱定义类语言,a可以是任意形态(str,int,object等等)。
def func(a):print('a是什么都可以')# 再比如:
class F1:passclass S1(F1):def show(self):print 'S1.show'class S2(F1):def show(self):print 'S2.show'# 由于在Java或C#中定义函数参数时,必须指定参数的类型
# 为了让Func函数既可以执行S1对象的show方法,又可以执行S2对象的show方法,所以,定义了一个S1和S2类的父类
# 而实际传入的参数是:S1对象和S2对象def Func(F1 obj):
"""Func函数需要接收一个F1类型或者F1子类的类型"""print obj.show()s1_obj = S1()
Func(s1_obj)  # 在Func函数中传入S1类的对象 s1_obj,执行 S1 的show方法,结果:S1.show

s2_obj = S2()
Func(s2_obj)  # 在Func函数中传入Ss类的对象 ss_obj,执行 Ss 的show方法,结果:S2.show

Python伪代码实现Java或C  # 的多态

多态举例

python中有一句谚语说的好,你看起来像鸭子,那么你就是鸭子。
对于代码上的解释其实很简答:
class A:def f1(self):print('in A f1')def f2(self):print('in A f2')class B:def f1(self):print('in A f1')def f2(self):print('in A f2')obj = A()
obj.f1()
obj.f2()obj2 = B()
obj2.f1()
obj2.f2()
# A 和 B两个类完全没有耦合性,但是在某种意义上他们却统一了一个标准。
# 对相同的功能设定了相同的名字,这样方便开发,这两个方法就可以互成为鸭子类型。# 这样的例子比比皆是:str  tuple list 都有 index方法,这就是统一了规范。
# str bytes 等等 这就是互称为鸭子类型。

鸭子类型

三 类的约束

⾸先, 你要清楚. 约束是对类的约束.

用一个例子说话:

公司让小明给他们的网站完善一个支付功能,小明写了两个类,如下:

class QQpay:def pay(self,money):print('使用qq支付%s元' % money)class Alipay:def pay(self,money):print('使用阿里支付%s元' % money)a = Alipay()
a.pay(100)b = QQpay()
b.pay(200)

但是上面这样写不太放方便,也不合理,老大说让他整改,统一一下付款的方式,小明开始加班整理:

class QQpay:def pay(self,money):print('使用qq支付%s元' % money)class Alipay:def pay(self,money):print('使用阿里支付%s元' % money)def pay(obj,money):  # 这个函数就是统一支付规则,这个叫做: 归一化设计。obj.pay(money)a = Alipay()
b = QQpay()pay(a,100)
pay(b,200)

写了半年的接口,小明终于接了大项目了,结果公司没品位,招了一个野生的程序员春哥接替小明的工作,老大给春哥安排了任务,让他写一个微信支付的功能:

class QQpay:def pay(self,money):print('使用qq支付%s元' % money)class Alipay:def pay(self,money):print('使用阿里支付%s元' % money)class Wechatpay:  # 野生程序员一般不会看别人怎么写,自己才是最好,结果......def fuqian(self,money):print('使用微信支付%s元' % money)def pay(obj,money):obj.pay(money)a = Alipay()
b = QQpay()pay(a,100)
pay(b,200)c = Wechatpay()
c.fuqian(300)

结果春哥,受惩罚了,限期整改,那么春哥,发奋图强,看了太白教你学python的相关资料,重新梳理的代码:

class Payment:   """ 此类什么都不做,就是制定一个标准,谁继承我,必须定义我里面的方法。   """def pay(self,money):passclass QQpay(Payment):def pay(self,money):print('使用qq支付%s元' % money)class Alipay(Payment):def pay(self,money):print('使用阿里支付%s元' % money)class Wechatpay(Payment):def fuqian(self,money):print('使用微信支付%s元' % money)def pay(obj,money):obj.pay(money)a = Alipay()
b = QQpay()pay(a,100)
pay(b,200)c = Wechatpay()
c.fuqian(300)

但是,这样还会有问题,如果再来野生程序员,他不看其他的支付方式,也不知道为什么继承的类中要定义一个没有意义的方法,所以他会是会我行我素:

class Payment: """ 此类什么都不做,就是制定一个标准,谁继承我,必须定义我里面的方法。"""def pay(self,money):passclass QQpay(Payment):def pay(self,money):print('使用qq支付%s元' % money)class Alipay(Payment):def pay(self,money):print('使用阿里支付%s元' % money)class Wechatpay(Payment):def fuqian(self,money):print('使用微信支付%s元' % money)def pay(obj,money):obj.pay(money)a = Alipay()
b = QQpay()pay(a,100)
pay(b,200)c = Wechatpay()
c.fuqian(300)

所以此时我们要用到对类的约束,对类的约束有两种:

1. 提取⽗类. 然后在⽗类中定义好⽅法. 在这个⽅法中什么都不⽤⼲. 就抛⼀个异常就可以了. 这样所有的⼦类都必须重写这个⽅法. 否则. 访问的时候就会报错.

2. 使⽤元类来描述⽗类. 在元类中给出⼀个抽象⽅法. 这样⼦类就不得不给出抽象⽅法的具体实现. 也可以起到约束的效果.

先用第一种方式解决:

class Payment:"""此类什么都不做,就是制定一个标准,谁继承我,必须定义我里面的方法。"""def pay(self,money):raise Exception("你没有实现pay方法")class QQpay(Payment):def pay(self,money):print('使用qq支付%s元' % money)class Alipay(Payment):def pay(self,money):print('使用阿里支付%s元' % money)class Wechatpay(Payment):def fuqian(self,money):print('使用微信支付%s元' % money)def pay(obj,money):obj.pay(money)a = Alipay()
b = QQpay()
c = Wechatpay()
pay(a,100)
pay(b,200)
pay(c,300)

第二种方式:引入抽象类的概念处理。

from abc import ABCMeta,abstractmethod
class Payment(metaclass=ABCMeta):    # 抽象类 接口类  规范和约束  metaclass指定的是一个元类
    @abstractmethoddef pay(self):pass  # 抽象方法class Alipay(Payment):def pay(self,money):print('使用支付宝支付了%s元'%money)class QQpay(Payment):def pay(self,money):print('使用qq支付了%s元'%money)class Wechatpay(Payment):# def pay(self,money):#     print('使用微信支付了%s元'%money)def recharge(self):passdef pay(a,money):a.pay(money)a = Alipay()
a.pay(100)
pay(a,100)    # 归一化设计:不管是哪一个类的对象,都调用同一个函数去完成相似的功能
q = QQpay()
q.pay(100)
pay(q,100)
w = Wechatpay()
pay(w,100)   # 到用的时候才会报错# 抽象类和接口类做的事情 :建立规范
# 制定一个类的metaclass是ABCMeta,
# 那么这个类就变成了一个抽象类(接口类)
# 这个类的主要功能就是建立一个规范

总结: 约束. 其实就是⽗类对⼦类进⾏约束. ⼦类必须要写xxx⽅法. 在python中约束的⽅式和⽅法有两种:

1. 使⽤抽象类和抽象⽅法, 由于该⽅案来源是java和c#. 所以使⽤频率还是很少的

2. 使⽤⼈为抛出异常的⽅案. 并且尽量抛出的是NotImplementError. 这样比较专业, ⽽且错误比较明确.(推荐)

四. super()深入了解

super是严格按照类的继承顺序执行!!!

class A:def f1(self):print('in A f1')def f2(self):print('in A f2')class Foo(A):def f1(self):super().f2()print('in A Foo')obj = Foo()
obj.f1()

super可以下一个类的其他方法

class A:def f1(self):print('in A')class Foo(A):def f1(self):super().f1()print('in Foo')class Bar(A):def f1(self):print('in Bar')class Info(Foo,Bar):def f1(self):super().f1()print('in Info f1')obj = Info()
obj.f1()'''
in Bar
in Foo
in Info f1
'''
print(Info.mro())  # [<class '__main__.Info'>, <class '__main__.Foo'>, <class '__main__.Bar'>, <class '__main__.A'>, <class 'object'>]

super()严格按照类的mro顺序执行

class A:def f1(self):print('in A')class Foo(A):def f1(self):super().f1()print('in Foo')class Bar(A):def f1(self):print('in Bar')class Info(Foo,Bar):def f1(self):super(Foo,self).f1()print('in Info f1')obj = Info()
obj.f1()

再来!

转载于:https://www.cnblogs.com/jin-xin/articles/10279154.html

04 面向对象之:三大特性:继承(已讲),封装,多态。相关推荐

  1. 面向对象之三大特性:继承,封装,多态

    python面向对象的三大特性:继承,封装,多态. 1. 封装: 把很多数据封装到⼀个对象中. 把固定功能的代码封装到⼀个代码块, 函数, 对象, 打包成模块. 这都属于封装的思想. 具体的情况具体分 ...

  2. 面向对象的三大特性————继承,多态

    1,继承:继承是一种创建新类的方式,在python中,新建的类可以继承一个或多个父类,父类又可称为基类或超类,新建的类称派生类或子类. 一个类可以被多个类继承,一个类可以继承多个父类. 没有继承父类默 ...

  3. 【Golang第8章:面向对象编程】Go语言的结构体是什么,怎么声明;Golang方法的调用和声明;go语言面向对象实例,go语言工厂模式;golang面向对象的三大特性:继承、封装、多态

    介绍 这个是在B站上看边看视频边做的笔记,这一章是Glang面向对象编程 这一章内容较多,内容有Go语言的结构体是什么,怎么声明:Golang方法的调用和声明:go语言面向对象实例,go语言工厂模式: ...

  4. 面向对象之:三大特性:继承(已讲),封装,多态

    目录 1.封装 2.多态 3.类的约束 4. super()深入了解 前言: python面向对象的三大特性:继承,封装,多态. 1. 封装: 把很多数据封装到⼀个对象中. 把固定功能的代码封装到⼀个 ...

  5. Python - 面向对象编程 - 三大特性之继承

    继承 继承也是面向对象编程三大特性之一 继承是类与类的一种关系 定义一个新的 class 时,可以从某个现有的 class 继承 新的 class 类就叫子类(Subclass) 被继承的类一般称为父 ...

  6. java面向对象:三大特性:封装,继承,多态

    -----------------------------------面向对象:三大特性:封装,继承,多态 ----------------------------------- 1.什么是类?什么是 ...

  7. Day55-每日一道Java面试题-Java 面向对象编程三大特性: 封装 继承 多态

    Java 面向对象编程三大特性: 封装 继承 多态 封装 封装把一个对象的属性私有化,同时提供一些可以被外界访问的属性的方法,如果属性不想被外界访问,我们大可不必提供方法给外界访问.但是如果一个类没有 ...

  8. 面向对象的三大特性之继承

    # 面向对象的三大特性之继承# 当类之间有显著不同,并且较小的类是较大的类所需要的组件时,用组合比较好 (如机器人) # 当类之间有很多相同的功能,提取这些共同的功能做成基类,用继承比较好 (动物-- ...

  9. 到底什么是面向对象,面试中怎么回答。面向过程和面向对象的区别是什么。java跨平台特性以及java和C++的区别。面向对象的三大特性——封装、继承和多态。面向对象的高拓展性以及低耦合度怎么体现?

    Java语言具有的特点:面向对象.跨平台.多线程以及网络编程 1. 和C++的区别 1.1 Java隐蔽了C++的指针,避免指针直接操作,程序更加安全. 1.2 Java类继承只能单继承,避免了C++ ...

最新文章

  1. ecshop模板smarty foreach详解 [ECshop]
  2. Java最全的思维导图汇总!速度收藏!
  3. 3a算法 isp_Isp图像算法工程师
  4. 【网易云信 x 齿轮易创】互联网时代,如何在教育行业抢占C位
  5. CRM One Order事件注册的准确位置
  6. 【CodeForces - 214C 】Game (拓扑排序,思维)
  7. 2020 年热门编程语言的发展方向
  8. AutoKeras使用
  9. html语言的字体设置
  10. ESP8266的AP模式与STA模式简单测试
  11. android自动运行服务,Android开机自启动服务的实现方法
  12. reinterpret_cast 最小demo
  13. ppt转html5原理,如何实现PPT转成H5?
  14. JavaScript实现贪吃蛇小游戏
  15. 【机房重构】-UNL图回顾
  16. 火车头过滤 css样式_HTML5和CSS3过滤器中的网络摄像头视频捕获
  17. Excel导入导出百万级数据
  18. linux 星际争霸,让星际争霸在Linux下转起来
  19. 小括号教学设计导入_《认识小括号》教学设计.doc
  20. zend 的render()

热门文章

  1. arch 服务器系统,arch linux服务器
  2. 世界文明史2019尔雅满分答案
  3. 小而美的LBS应用龙门阵——成都开发者沙龙
  4. C#模仿腾讯QQ源码下载(附效果图)_张童瑶的博客
  5. python计算存款复利计算器_分享下自己写的计算余额宝上复利的代码,网上的复利计算器无法满足需求...
  6. Siri怎么重置主人声音
  7. 塔式、刀片和机架:三种类型的服务器介绍
  8. ROM,PROM,EPROM,EEPROM及FLASH存储器的区别
  9. AMD三季度营收创新高,借数据中心业务与英特尔打响5G前哨战?
  10. signature=755e8ee7e865b95708ea6b30aedefbd3,fMRI of Language Systems