Python()- 面向对象三大特性----继承
继承:
继承是一种创建新类的方式,
在python中,新建的类可以继承一个或多个父类(基类或超类),新建的类是所继承的类的(派生类或子类)
人类和狗 有相同的属性, 提取了一个__init__方法,在这个方法里放一些共有的属性
人类和狗 在相同的方法,提取了一个def func():方法,在这个方法里放一些共有的方法
单继承和多继承
class Par1:
pass
class Par2:
pass
class Sub1(Par1):
pass
class Sub2(Par1,Par2):
pass
#__base__只查看从左到右的第一个父类,而__bases__查看所有父类
print(Sub1.__bases__)
#(<class '__main__.Par1'>,)
print(Sub2.__bases__)
#(<class '__main__.Par1'>, <class '__main__.Par2'>)
------------------------------------
print(Par1.__base__)
#<class 'object'>
如果没有指定基类,python的类默认继承object类,object类是所有类的基类,它提供了一些常见的方法(如__str__)的实现
class Par1:
def __init__(self,name):
self.name = name
def __str__(self):
return self.name
p = Par1('kitty')
print(p)
# kitty
class Foo1:
def __init__(self,name): # self是f对象
self.name = name
def __str__(self):
return self.name
class Foo2(Foo1):
a = 1
f = Foo2('kitty') #Foo2中没有__init__函数,就去基类去找,然后传入参数
print(f.name) # kitty
继承与抽象:
世间本来没有人类,只是很多个具体的人对象,后来把所有的人抽象成(划规成)一类,才有了人类的概念
so: 抽象是从下往上
继承从上往下
继承与重用性:
继承的目的是为了减少代码的重复性
比如:
想创建一个b类, 但是发现b类的属性大部分和a类的相同, 就让b去继承a的属性,节省代码
提示:用已经有的类建立一个新的类,这样就重用了已经有的软件中的一部分设置大部分,大大生了编程工作量,这就是常说的软件重用,不仅可以重用自己的类,也可以继承别人的,比如标准库,来定制新的数据类型,这样就是大大缩短了软件开发周期,对大型软件开发来说,意义重大.
经典类 和 新式类:
python3都是新式类 (新式类默认继承object class Foo(object): == class Foo: )
python2中经典类和新式类共存
- class Foo: 是经典类
- class Foo(object): 是新式类
钻石继承:
- 经典类: 深度优先,就是单线走到头,再去其它线
- 新式类: 就是单线走到剩余最后一个父类停止,再去找其它线,最后一条线走到尾
经典类继承顺序:
深度优先
新式类继承顺序:
广度优先:
如果找到b就去找c c再去找e e在去找f f没有就报错了 因为f找不到d 单线
=====================================================
python2 中: 最原始的加上object,往后的都会继承object
======================================
再来看:
class D:
def __init__(self):
print('d')
class C(D):
def __init__(self):
print('c')
super().__init__()
class B(D):
def __init__(self):
print('b')
super().__init__()
class A(B,C):
def __init__(self):
print('a')
super().__init__()
#mro
a = A()
print(A.mro())
##结果如下:
a
b
c
d
[<class '__main__.A'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.D'>, <class 'object'>]
和mro的顺序一样 广度优先 (super只有新式类中有)
在多继承中,super不只是寻找当前类的父类,而是依据mro顺序,
从A节点出发,根据广度优先排序查找下一个类
Mixin
在设计类的继承关系时,通常,主线都是单一继承下来的,例如,Ostrich继承自Bird。但是,如果需要“混入”额外的功能,通过多重继承就可以实现,比如,让Ostrich除了继承自Bird外,再同时继承Runnable。这种设计通常称之为Mixin。
为了更好地看出继承关系,我们把Runnable和Flyable改为RunnableMixin和FlyableMixin。类似的,你还可以定义出肉食动物CarnivorousMixin和植食动物HerbivoresMixin,让某个动物同时拥有好几个Mixin:
class Dog(Mammal, RunnableMixin, CarnivorousMixin):
pass
Mixin的目的就是给一个类增加多个功能,这样,在设计类的时候,我们优先考虑通过多重继承来组合多个Mixin的功能,而不是设计多层次的复杂的继承关系。
Python自带的很多库也使用了Mixin。举个例子,Python自带了TCPServer和UDPServer这两类网络服务,而要同时服务多个用户就必须使用多进程或多线程模型,这两种模型由ForkingMixin和ThreadingMixin提供。通过组合,我们就可以创造出合适的服务来。
比如,编写一个多进程模式的TCP服务,定义如下:
class MyTCPServer(TCPServer, ForkingMixin):
pass
编写一个多线程模式的UDP服务,定义如下:
class MyUDPServer(UDPServer, ThreadingMixin):
pass
如果你打算搞一个更先进的协程模型,可以编写一个CoroutineMixin:
class MyTCPServer(TCPServer, CoroutineMixin):
pass
这样一来,我们不需要复杂而庞大的继承链,只要选择组合不同的类的功能,就可以快速构造出所需的子类。
总结:
由于Python允许使用多重继承,因此,Mixin就是一种常见的设计。只允许单一继承的语言(如Java)不能使用Mixin的设计。
派生
派生:
class A: # 基类(提取了狗和人的共同属性)
def __init__(self,name, aggressivity, life_value): #里面的self是对象
self.name = name
self.aggressivity = aggressivity
self.life_value = life_value
def eat(self):
print('A eating')
class Dog(A): # 定义一个狗类
def __init__(self,name, aggressivity, life_value,breed,): #派生一个__init__方法
#A.__init__(self,name, aggressivity, life_value) : 类名.__init__(参数)
super().__init__(name, aggressivity, life_value) #调用基类__init__方法:super().__init__()
self.breed = breed # 每一只狗都有自己的品种;
def bite(self,people): #派生bite方法 父类中没有的属性&方法
people.life_value -= self.aggressivity
def eat(self): #重新定义eat (派生)
A.eat(self) #如果想加上父类的方法: A.eat(对象)
print('dog eating')
class Person(A): # 定义一个人类
def __init__(self,name, aggressivity, life_value,money): #派生
super().__init__(name, aggressivity, life_value) #调用基类__init__方法
self.money = money
def attack(self,dog):
dog.life_value -= self.aggressivity
def get_weapon(self,weapon_obj):
if self.money > weapon_obj.price:
self.money -= weapon_obj.price # 金老板花钱买武器
self.weapon = weapon_obj # 金老板装备打狗棒
self.aggressivity += weapon_obj.aggr # 金老板的攻击力增加了
jin = Person('jin',250,250,100)
dog = Dog('酷狗',33,50,'藏獒')
print(jin.name) # jin
print(jin.money) #
print(dog.name) # 酷狗
print(dog.breed) # 藏獒
dog.eat()
# A eating
# dog eating
-------------------
A.eat(dog) #A eating #类名.方法名(对象名)
--------------------------------
super(Dog,dog).eat() #A eating super(类名,对象名) super在外面用,必须传参数
派生方法和属性:
1.在子类中增加父类没有的
2.如果再调用父类的的方法和属性
父类.__init__(self,参数...) ⇒ 指名道姓调用
super()__init__(参数...)
在类外面用super的时候, super(子类名,对象).属性
小结:
子类有,用自己的,没有用父类的
子类有,父类有,仍然想用父类的:
经典类: 父类.__init__(self,参数...) 父类.方法名(对象)
新式类: super().__init__(参数...) 父类.方法名(对象)
一般情况下super都满足了
指名道姓调用父类的方法 父类.方法(self) self是子类的对象
例题:打印结果
class Foo:
def __init__(self): (self是对象,对象自己有func())
self.func()
def func(self):
print('父类')
class Son(Foo):
def func(self):
print('子类')
s = Son()
#子类
----------------
print(Son.mro()) 新式类才有的查看继承顺序的方法: print(类名.mro())
[<class '__main__.Son'>, <class '__main__.Foo'>, <class 'object'>]
接口类:
接口类:多继承,父类不实现
(模板:都按我的来,这是约定好的)
=================================
格式:
from abc import ABCMeta, abstractmethod
class Foo(metaclass=ABCMeta)
@abstractmethod
def func(self,money):pass
=============================
# 是规范子类的一个模板,只要接口类中定义的,就应该在子类中必须实现
# 接口类不能被实例化,它只能被继承
# 支持多继承
from abc import ABCMeta, abstractmethod class Payment(metaclass=ABCMeta): # 模板,接口类 metaclass 元类 先不用深究
@abstractmethod # 装饰接口类中方法, 加上这个装饰器,自动检测子类中的方法名
def pay(self, money): pass # def get(self):pass 接口类有,下面子类必须有,如果包含没有@abstractmethod的方法,就不是接口类,而是抽象类 class Apple_Pay(Payment):
def pay(self, money):
print('您使用苹果支付支付了%s元' % money) def func(self):
print('类自己的方法') class Ali_Pay(Payment):
def pay(self, money):
print('您使用支付宝支付了%s元' % money) class WeChat_Pay(Payment):
def pay(self, money):
print('您使用微信支付了%s元' % money) def pay(obj, money):
return obj.pay(money) # 这个pay是和类里面的一一对应的 apple = Apple_Pay()
ali = Ali_Pay()
wechat = WeChat_Pay() pay(apple, 100) # apple.pay(100)
pay(wechat, 200)
===========
def pay(obj,money):
return obj.pay(money) 类似:
def next(obj):
return obj.__next_() __next__() next() 内置函数
=======================================
接口类: 主动触发异常
class Payment(Payment):
def pay(self,money):raise NotImplementedError
(这个方法有个缺点,子类只有调用那个方法时才会抛错,推荐@abstractmethod,可以在类被实例化后触发它)
..................下面代码省略...........
报错
def pay(self,money):raise NotImplementedError
NotImplementedError
=========================================
===============
接口的多继承:
接口隔离原则:使用多个专门的接口,而不使用单一的总接口.(客户端不应该依赖那些不需要的接口)
(模板不能放到一个里面)
(接口类鼓励多继承) # (抽象类避免多继承)
===========================================
python 本来没有接口类, 接口类的@abstractmethod 是借用的 抽象类的模块(装饰器)来实现接口类
接口类概念来自java
抽象类:
模板 规范
抽象类可以实现一些子类共有的功能和属性\抽象类避免多继承
python 没有接口的概念
只能借助抽象类的模块 来实现接口类
---------------------------------------------------------
接口 —— 来自java,但是java没有多继承 , java有个Interface关键字,
---------------------------------------------------------
例子:
文件操作 :打开文件 关闭文件 写文件 读文件
硬盘操作:打开,关闭,写 读
进程文件:打开 关闭,读 写
都有打开,关闭,读取,写入的功能
from abc import ABCMeta,abstractmethod #格式参考接口类格式
class Base(metaclass=ABCMeta):
def __init__(self,filename): #抽象类可以有__init_(), 接口类不能有 其它的没感觉两个有有啥区别
self.filename = filename
@abstractmethod #抽象方法
def open(self):
return 'file_handler' @abstractmethod
def close(self):pass @abstractmethod
def read(self):pass @abstractmethod
def write(self):pass class File(Base):
def open(self):pass
def close(self):pass
def read(self):pass
def write(self):pass
抽象类不能被实例化
这个抽象类可以规范子类必须实现抽象类中的抽象方法 (没有强制子类必须有父类的所有方法)
例二: 原博客地址: https://www.cnblogs.com/bjdxy/archive/2012/11/15/2772119.html
由于python 没有抽象类、接口的概念,所以要实现这种功能得abc.py 这个类库,具体方式如下
from abc import ABCMeta, abstractmethod #抽象类
class Headers(object):
__metaclass__ = ABCMeta def __init__(self):
self.headers = ' ' @abstractmethod
def _getBaiduHeaders(self):pass def __str__(self):
return str(self.headers) def __repr__(self):
return repr(self.headers) #实现类
class BaiduHeaders(Headers):
def __init__(self, url, username, password):
self.url = url
self.headers = self._getBaiduHeaders(username, password) def _getBaiduHeaders(self, username, password):
client = GLOBAL_SUDS_CLIENT.Client(self.url)
headers = client.factory.create('ns0:AuthHeader')
headers.username = username
headers.password = password
headers.token = _baidu_headers['token']
return headers
如果子类不实现父类的_getBaiduHeaders方法,则抛出TypeError: Can't instantiate abstract class BaiduHeaders with abstract methods 异常
===============================================
抽象类和接口类的区别
python的语法角度上来说,是没有区别的,(因为没有接口类的概念,接口类借用抽象类的概念和模块)
小区别:接口类不能实现内部的代码,
抽象类能实现司内部的代码(__init__())
应用场景的不同:
抽象类不鼓励多实现(少继承)
接口类鼓励多实现(多继承)
所以一般情况下,没有法子通过代码上的不同去区分它们,只能通过应用场景去区分它们.(一种思想上的改变)
抽象类的本质还是类,指的是一组类的相似性,包括数据属性(如all_type)和函数属性(如read、write),
而接口只强调函数属性的相似性。
抽象类是一个介于类和接口之间的一个概念,同时具备类和接口的部分特性,可以用来实现归一化设计
================================================
Python()- 面向对象三大特性----继承的更多相关文章
- [.net 面向对象编程基础] (12) 面向对象三大特性——继承
[.net 面向对象编程基础] (12) 面向对象三大特性——继承 上节我们说了面向对象的三大特性之一的封装,解决了将对同一对象所能操作的所有信息放在一起,实现统一对外调用,实现了同一对象的复用,降低 ...
- python 面向对象三大特性(封装 多态 继承)
今天我们来学习一种新的编程方式:面向对象编程(Object Oriented Programming,OOP,面向对象程序设计)注:Java和C#来说只支持面向对象编程,而python比较灵活即支持面 ...
- python学习-64 面向对象三大特性----继承1
面向对象三大特性 1.三大特性? 继承,多态,封装 2.什么是继承? 类的继承和现实生活中的父与子,继承关系是一样的,父类为基类. python中的类继承分为:单继承和多继承 3.举例说明 class ...
- python 面向对象(三大特性)
python 面向对象(初级) (思维导图 ↑↑↑↑↑) 概述: 面向过程:根据业务逻辑从上到下垒代码. 函数式:将某功能代码封装至函数中,日后便无需重复编写,仅调用函数即可 面向对象:对函数进行分类 ...
- python面向对象三大特性
面向对象的三大特性: 封装.继承和多态 一.封装 封装,顾名思义就是将内容封装到某个地方,以后可以直接调用被封装到某处的内容. - 将内容封装到某处 - 从某处调用被封装的内容 第一步,将内容封装到某 ...
- Python入门-面向对象三大特性-继承
面向对象中的继承和现实生活中的继承相同,即:子可以继承父的内容. 例如: 猫可以:喵喵叫.吃.喝.拉.撒 狗可以:汪汪叫.吃.喝.拉.撒 如果我们要分别为猫和狗创建一个类,那么就需要为 猫 和 狗 实 ...
- python面向对象-三大特性
python面向对象编程三大特性 小结:前面我们说完了类和对象的关系,相信对类和对象的理解更加透彻..让我们一起去研究面向对象的三大特性吧.... 继承 1.什么继承? 在程序中继承就是事物之间的所属 ...
- python之面向对象三大特性: 继承(单继承)
什么是继承 专业角度: B 继承 A类, B就叫做A的子类,派生类, A叫做B的父类,基类,超类. B类以及B类的对象使用A类的所有的属性以及方法. 字面意思: 继承就是继承父母所有的资产 class ...
- python面向对象三大特性之继承
继承是创建新类的方法,以下是几个概念 父类,基类,超类: 被继承的类 子类,派生类:继承而产出的类 单继承:继承一个父类 多继承:继承多个父类 继承: 什么是什么的关系 父类中没有的属性,在字类中出现 ...
随机推荐
- js数组遍历的常用的几种方法以及差异和性能优化
<script type="text/javascript"> /*对比: 1.map速度比foreach快 2.map会返回一个新数组,不对原数组产生影响,forea ...
- 前端什么是BFC
什么是BFC? 全称块级格式化上下文?什么意思不懂.看了好多博客,基本都是抄的,真心都不是大白话.我今天来总结一下,用菜鸟级别的语言来描述. BFC 应该可以抽象成一个 独立的个体,出淤泥而不染的白莲 ...
- 关于html页面元素语义化的一点思考
这几天在看招聘公告前端工程师的要求基本都附带了html语义化的要求,所以稍微关注了下这方面的知识.对于其中的一点就是要求页面元素在去除css样式之后还能有良好的布局引发了我一点思考.作为前端刚入门的我 ...
- easyui实现增删改查
陈旧的开发模式 美工(ui工程师:出一个项目模型) java工程师:将原有的html转成jsp,动态展示数据 缺点: 客户需要调节前端的展示效果 解决:由美工去重新排版,重新选色. 前后端分离: 前端 ...
- Caused by: java.lang.IllegalArgumentException: Parameter Maps collection does not contain value for com.bj186.crm.mapper.UserMapper.Integer
在使用SSM整合myBatis的过程中遇到了这个问题. 问题的原因: 把parameterType错误的写成了parameterMap 解决办法: 将parameterMap修改为parameterT ...
- OpenCV2:第七章 图像处理
一.简介 灰度图(灰阶图),把白色到黑色之间分为256阶灰度 彩色图有RGB三个分量,假设图是800*800像素,那么就有三个800*800的矩阵分别代表RGB 二值化处理设定阈值,在阈值中的像素值变 ...
- oc学习
http://www.cnblogs.com/qingyuan/p/3524678.html
- layui二次封装
最近一直用layui进行页面的重构,这个框架十分适合我们后台人员开发.简单易用,但是layui本身不支持双向绑定,所以很多情况下,我们在支持动态的控件加载时,需要反复刷新.这里我自己封装了一个comm ...
- kvm安装图终端界面及形界面安装系统
1.图形界面安装: qemu-img create -f qcow2 /kvm/os/vm-01.qcow2 16G mkdir -p /kvm/iso cd /kvm/iso 上传事先下载好的镜像文 ...
- JavaScript:对Object对象的一些常用操作总结
JavaScript对Object对象的一些常用操作总结. 一.Object.assign() 1.可以用作对象的复制 var obj = { a: 1 }; var copy = Object.as ...