day 25-1 接口类、抽象类、多态
# 接口类:python 原生不支持
# 抽象类:python 原生支持的
接口类
首先我们来看一个支付接口的简单例子
from abc import abstractmethod,ABCMeta #我们也可以创建一个规范类
class Payment(metaclass=ABCMeta): # 元类 默认的元类 type
@abstractmethod
def pay(self,money):
raise Notlmplemented #规范类要求需要实现一个 叫做 pay 的方法
#这样在不调用的情况下 就会抛出错误 在实例化时就可以发现这个问题 # 规范 :接口类或者抽象类都可以
# 接口类 支持多继承,接口类中的所有的方法都必须不能实现 —— java
# 抽象类 不支持多继承,抽象类中方法可以有一些代码的实现 —— java class Payment:
def pay(self,money): #2.没有实现该方法,就会抛出这个异常,用来隐藏 1 处的错误
raise Notlmplemented #原理就是 如果不实现 pay 方法 就会抛出这个报错
#报错如下
#NameError: name 'Notlmplemented' is not defined class Weipay(Payment):
def pay(self,money):
print('微信支付了%s元'%money) class Alipay(Payment):
def pay(self,money):
print('支付宝支付了%s元'%money) class Apppay(Payment):
def pays(self,money): #1.如果这里的 pay 换成了其他名字就会报错 与下面的 pay 函数冲突了
print('苹果支付了%s元'%money)
wei = Weipay()
ali = Alipay()
app = Apppay() def pay(pay_obj,money):
pay_obj.pay(money) pay(wei,100)
pay(ali,100)
pay(app,100)
#weipay.pay(100)
#alipay.pay(100)
接口类的多继承
这是三种动物
tiger 走路 游泳
swan 走路 游泳 飞
oldying 走路 飞
为了避免代码重复,我们写以下三个类
下面就是实现了 接口类的规范 不需要有功能实现的代码
#下面就是实现了 接口类的规范 不需要有功能实现的代码
from abc import abstractmethod,ABCMeta
class Swim_Animal(metaclass=ABCMeta):
@abstractmethod
def swim(self):pass class Walk_Animal(metaclass=ABCMeta):
@abstractmethod
def walk(self):pass class Fly_Animal(metaclass=ABCMeta):
@abstractmethod
def fly(self):pass #继承了类里面的相应的方法就必须要写
class Tiger(Walk_Animal,Swim_Animal):
def walk(self):
pass
def swim(self):
pass
class OldYing(Fly_Animal,Walk_Animal):pass
class Swan(Swim_Animal,Walk_Animal,Fly_Animal):pass # 这样就完了 接口类 刚好满足接口隔离原则 面向对象开发的思想 规范
python 中没有接口类 这个只是类似,就是说 我要实现不同的功能,我就去继承不同的接口,来规范我当前类中要用那些函数
好了我们接下来稍稍完善下上满的例子
from abc import abstractmethod,ABCMeta
class Swim_Animal(metaclass=ABCMeta):
@abstractmethod
def swim(self):pass class Walk_Animal(metaclass=ABCMeta):
@abstractmethod
def walk(self):pass class Fly_Animal(metaclass=ABCMeta):
@abstractmethod
def fly(self):pass class Tiger(Walk_Animal,Swim_Animal):
def walk(self,num):
print('狮子跑了 %s 公里'%num)
def swim(self,num):
print('狮子游了 %s 公里'%num) class OldYing(Fly_Animal,Walk_Animal):
def fly(self,num):
print('老鹰飞了 %s 公里'%num)
def walk(self,num):
print('老鹰跑了 %s 公里'%num) class Swan(Swim_Animal,Walk_Animal,Fly_Animal):
def fly(self,num):
print('天鹅飞了 %s 公里'%num)
def walk(self,num):
print('天鹅跑了 %s 公里'%num)
def swim(self,num):
print('天鹅游了 %s 公里'%num) T = Tiger()
o = OldYing()
s = Swan()
#s.fly(5) def action(action_obj,num):
action_obj(num) action(s.fly,5)
抽象类
如果说类是从一堆对象中抽取相同的内容而来的,那么抽象类就是从一堆类中抽取相同的内容而来的,内容包括数据属性和函数属性
在 python 中实现抽象类,抽象类一般是单继承
操作系统一切皆文件
我们来实现一个抽象类
import abc #利用 abc 模块实现抽象类 class All_file(metaclass=abc.ABCMeta):
all_type='file'
@abc.abstractmethod #定义抽象方法,无需实现功能
def read(self):
'子类必须定义读功能'
with open('filaname') as f:
pass @abc.abstractmethod #定义抽象方法,无需实现功能
def write(self):
'子类必须定义写功能'
pass class Txt(All_file): #子类继承抽象类,但是必须定义read和write方法
def read(self):
print('文本数据的读取方法')
def write(self):
print('文本数据的读取方法') class Sata(All_file): #子类继承抽象类,但是必须定义read和write方法
def read(self):
print('硬盘数据的读取方法') def write(self):
print('硬盘数据的读取方法') class Process(All_file): #子类继承抽象类,但是必须定义read和write方法
def read(self):
print('进程数据的读取方法') def write(self):
print('进程数据的读取方法') wenbenwenjian=Txt() yingpanwenjian=Sata() jinchengwenjian=Process() #这样大家都是被归一化了,也就是一切皆文件的思想
wenbenwenjian.read()
yingpanwenjian.write()
jinchengwenjian.read() print(wenbenwenjian.all_type)
print(yingpanwenjian.all_type)
print(jinchengwenjian.all_type)
抽象类 : 规范
一般情况下 单继承 能实现的功能都是一样的,所以在父类中可以有一些简单的基础实现
多继承的情况 由于功能比较复杂,所以不容易抽象出相同的功能的具体实现写在父类中
抽象类还是接口类 : 面向对象的开发规范 所有的接口类和抽象类都不能实例化
java:
java里的所有类的继承都是单继承,所以抽象类完美的解决了单继承需求中的规范问题
但对于多继承的需求,由于java本身语法的不支持,所以创建了接口Interface这个概念
来解决多继承的规范问题
python:
python中没有接口类 :
python中自带多继承 所以我们直接用class来实现了接口类
python中支持抽象类 : 一般情况下 单继承 不能实例化(接口类抽象类)
且可以实现python代码
多态
python 天生支持多态,python 是动态强类型的语言
多态指的是一类事物有多种形态
动物有多种形态:人,狗,猪
import abc
class Animal(metaclass=abc.ABCMeta): #同一类事物:动物
@abc.abstractmethod
def talk(self):
pass class People(Animal): #动物的形态之一:人
def talk(self):
print('say hello') class Dog(Animal): #动物的形态之二:狗
def talk(self):
print('say wangwang') class Pig(Animal): #动物的形态之三:猪
def talk(self):
print('say aoao') People().talk()
文件有多种形态:文本文件,可执行文件
多态性
什么是多态动态绑定(在继承的背景下使用时,有时也称为多态性)
多态性是指在不考虑实例类型的情况下使用实例
在面向对象方法中一般是这样表述多态性:
向不同的对象发送同一条消息( !!!obj.func():是调用了obj的方法func,又称为向 obj 发送了一条消息 func ),不同的对象在接收时会产生不同的行为(即方法)。 也就是说,每个对象可以用自己的方式去响应共同的消息。所谓消息,就是调用函数,不同的行为就是指不同的实现,即执行不同的函数。 比如:老师.下课铃响了(),学生.下课铃响了(),老师执行的是下班操作,学生执行的是放学操作,虽然二者消息一样,但是执行的效果不同
鸭子类型
# 鸭子类型
# list tuple 如果说两个类型为鸭子类型 就是说这两个类型很相识
# 不崇尚根据继承所得来的相似
# 我只是自己实现我自己的代码就可以了。
# 如果两个类刚好相似,并不产生父类的子类的兄弟关系,而是鸭子类型
# list tuple 这种相似,是自己写代码的时候约束的,而不是通过父类约束的
# 优点:松耦合 每个相似的类之间都没有影响
# 缺点:太随意了,只能靠自觉
# 接口类和抽象类 在 python 当中的应用点并不是非常必要
封装
# 广义上面向对象的封装 :代码的保护,面向对象的思想本身就是一种
# 只让自己的对象能调用自己类中的方法
# 狭义上的封装 —— 面向对象的三大特性之一
# 属性 和 方法都藏起来 不让你看见
class Person:
__key = 123 # 私有静态属性
def __init__(self,name,passwd):
self.name = name
#self.passwd = passwd
self.__passwd = passwd #当属性前面加上 __ 就成为了私有属性 def get_pwd(self): #在类的内部使用方法调用 __passwd 属性
print(self.__dict__)
return self.__passwd #只要在类的内部使用私有属性,就会自动的带上_类名 def __login(self): #私有方法
self.__get.pwd() per = Person('ysg','')
#print(alex.passwd)
#print(per.__passwd) #然后就找不到该属性了
print(per.__dict__) #这里还是可以看到 所有私有属性并不是约束数据安全的只是在代码级别加了一层密
print(per._Person__passwd) # _类名__属性名 这样调用就可以了 不过不应该去调取
print(per.get_pwd()) print(per.__login) #调取不到
#定义类的私有属性 只能在类的内部 外部就不可以
per.__high = 1
print(per.__high) #外部就可以直接使用
所有的私有 都是在变量的左边加上双下划线
对象的私有属性
类中的私有方法
类中的静态私有属性
所有的私有的 都不能在类的外部使用
封装之隐藏
如何隐藏:在 python 中用双下划线开头的方式将属性隐藏起来(设置成私有的)
class A:
__x = 1 def __init__(self, name):
self.name = name def __foo(self):
print('this is foo') #print(A.__x)
# AttributeError: type object 'A' has no attribute '__x'
a = A('ysg')
print(a.name) # ysg
#print(A.__foo) #AttributeError: type object 'A' has no attribute '__foo' # 我们来查看下 class A 的属性
# 可以看到并没有 __x、__foo 的属性,但有了 _A__x、_A__foo 的属性
print(A.__dict__) #{'__module__': '__main__', '_A__x': 1, '__init__': <function A.__init__ at 0x000001D63A0602F0>, '_A__foo': <function A.__foo at 0x000001D63A0BB268>,,...}
如上,我们可以大胆的猜测一下,当我们使用双下划线隐藏后,它可能做了某种变形,我们来尝试下
print(A._A__x) # 1
print(A._A__foo) # <function A.__foo at 0x000001D26E09D1E0>
可以看出,的确是做了变形的处理
接下来看下它有哪些特点:
- 类中定义的 __x 只能在内部使用,如 self.__x,引用的就是变形的结果
- 这种变形其实正是针对外部的变形,在外部无法通过 __x 这个名字访问到
- 在子类定义的 __x 不会覆盖在父类定义的 __x,因为子类中变形成了:_子类名__x,而父类中变形成了:_父类名__x,即双下滑线开头的属性在继承给子类时,子类是无法覆盖的
这种变形需要注意的问题是:
- 这种机制也并没有真正意义上限制我们从外部直接访问属性,知道了类名和属性名就可以拼出名字:_类名__属性,然后就可以访问了,如a._A__N
- 变形的过程只在类的定义是发生一次,在定义后的赋值操作,不会变形
- 在继承中,父类如果不想让子类覆盖自己的方法,可以将方法定义为私有的
我们用一个例子来验证下
class B:
def __foo(self):
print('B.foo') def bar(self):
print('B.bar')
self.__foo() class C(B):
def __foo(self):
print('C.foo') c = C()
c.bar() # 结果:
B.bar
B.foo
封装不是单纯意义的隐藏
1.封装数据属性:明确区分内外,控制外部对隐藏属性的操作
将数据隐藏起来这不是目的。隐藏起来然后对外提供操作该数据的接口,然后我们可以在接口附加上对该数据操作的限制,以此完成对数据属性操作的严格控制
我们来写一个例子
class People:
def __init__(self, name, age):
self.__name = name
self.__age = age def tell_info(self):
print('Name:<%s>\nAge:<%s>' % (self.__name, self.__age)) def set_info(self, name, age):
if not isinstance(name, str):
print('名字必须是字符串类型')
return
if not isinstance(age, int):
print('年龄必须是 int 类型')
return
self.__name = name
self.__age = age p = People('ysg', 16)
p.tell_info()
# Name:<ysg>
# Age:<16> p.set_info(123, 18) # 名字必须是字符串类型
p.tell_info()
p.set_info('er', '18') # 年龄必须是 int 类型
p.tell_info()
# Name:<ysg>
# Age:<16> p.set_info('er', 18)
p.tell_info()
# Name:<er>
# Age:<18>
上面可以看到:
tell_inso() 实现了在不能直接查看属性时,开一个接口且按照一定的规格进行查看属性
set_info() 实现了在不能直接修改属性时,开一个接口且对传来的属性进行判断,通过则进行修改
2.封装方法:隔离复杂度
我们来看下面的例子
1.取款是功能,而这个功能有很多功能组成:插卡、密码认证、输入金额、打印账单、取钱
2.对使用者来说,只需要知道取款这个功能即可,其余功能我们都可以隐藏起来,很明显这么做
3.隔离了复杂度,同时也提升了安全性
class ATM:
def __card(self):
print('插卡') def __auth(self):
print('用户认证') def __input(self):
print('输入取款金额') def __print_bill(self):
print('打印账单') def __take_money(self):
print('取款') # 实现了只通过这一个接口来完成上面流程的调用
def withdraw(self):
self.__card()
self.__auth()
self.__input()
self.__print_bill()
self.__take_money() a = ATM()
a.withdraw()
注意:在编程语言里,对外提供的接口(接口可理解为了一个入口),可以是函数,称为接口函数,这与接口的概念还不一样,接口代表一组接口函数的集合体
封装与可扩展性
封装在于明确区分内外,使得类实现者可以修改封装内的东西而不影响外部调用者的代码;而外部使用用者只知道一个接口(函数),只要接口(函数)名、参数不变,使用者的代码永远无需改变。这就提供一个良好的合作基础——或者说,只要接口这个基础约定不变,则代码改变不足为虑
class Room:
def __init__(self,name,owner,weight,length,height):
self.name=name
self.owner=owner # 这里访问者其实是要结果,值可以隐藏起来
self.__weight=weight
self.__length=length
self.__height=height #在这里改变运算规则
def tell_area(self):
return self.__weight * self.__length * self.__height r=Room('卫生间','alex',10,10,10) # print(r.tell_area()) #用户调用方式不变
print(r.tell_area())
达到了:对外提供的接口中,隐藏了内部的实现细节;扩展了功能,但不需要改变调用的方法
day 25-1 接口类、抽象类、多态的更多相关文章
- python开发面向对象基础:接口类&抽象类&多态&钻石继承
一,接口类 继承有两种用途: 一:继承基类的方法,并且做出自己的改变或者扩展(代码重用) 二:声明某个子类兼容于某基类,定义一个接口类Interface,接口类中定义了一些接口名(就是函数名)且并未实 ...
- Python_015(面向对象(接口类,抽象类,多态,封装)
一.抽象类与接口类 1.抽象类:抽象即类似或者说比较像的部分,继承描述的是父类与子类的一种关系,要找出这种关系,必须先抽象再继承; a:抽象分成两个层次: 1)由对象->类:将两个有相似地方的对 ...
- day27 多态 多继承 接口类 抽象类
简单来说:多态就是指一个相同的方法名在不同的对象调用的时候实现一样或者不一样的方法实例1: 动物类有个方法 "嚎叫" 狗类也有个方法 "嚎叫" 猫类继承了动物类 ...
- python笔记5 接口类抽象类 封装 反射 设计模式 模块 :random随机数 josn shelve持久化存储
接口类抽象类 接口类:接口类就是制定一个规则,让其他人按照我的规则去写程序. #!/usr/bin/env python from abc import ABCMeta,abstractmethod ...
- 日历类和日期类转换 并发修改异常 泛型的好处 *各种排序 成员和局部变量 接口和抽象类 多态 new对象内存中的变化
day07 ==和equals的区别? ==用于比较两个数值 或者地址值是否相同. equals 用于比较两个对象的内容是否相同 String,StringBuffer.StringBuilde ...
- python's twenty-first day for me 抽象类和接口类以及多态
归一化设计: 不管是哪一个类的对象,都调用同一个函数去完成相似的功能. class Alipay: def pay(self,money): print('使用支付宝支付了%s' % money) c ...
- Python进阶-XVII 非python的接口类、多态、python自己的封装
1.python模拟java中的接口类 python中是没有接口类的概念的,因为它支持多继承,但是java不能,所以就提出一个接口类的概念 java : 面向对象编程 设计模式 —— 接口 接口类 : ...
- php中普通类 接口类 抽象类 浅谈
一.普通类 1.关键词:class 类名,继承关键字extends 2.继承:只能实现单继承, 3.多态:子类继承可以实现多种功能 4.封装:类有权限机制,私有的只能自己用,受保护的可以被继承,子类 ...
- python学习之老男孩python全栈第九期_day025知识点总结——接口类、抽象类、多态、封装
一. 接口类 java:面向对象编程 设计模式 -- 接口类 接口类:python原生不支持 抽象类:python 原生支持的 from abc import abstractclassmethod, ...
随机推荐
- Linux:Day18(上) dns服务基础进阶
DNS:Domain Name Service,协议(C/S,53/udp,53/tcp):应用层协议. BIND:Bekerley Internat Name Domain,ISC(www.isc. ...
- An interesting combinational problem
A question of details in the solution at the end of this post of the question is asked by me at MSE. ...
- Linux系统安装jdk教程
本文仅仅适用于刚刚接触Linux系统的童鞋,毕竟本人也才刚刚玩这个东西,在此记录下以便于以后能查阅及其他童鞋能进行参考,本文为原创随笔,如需转发,请标明出处,谢谢: 此处我采用的是用VMware搭建的 ...
- c#枚举位运算操作
抛出预设问题 需要有一个npc需要在一周中的,周一,周二,周三会出现,其他时间不可见 解决问题 因为一周时间是固定的,所以创建枚举类型比较合适,如下 enum Days { None, Sunday, ...
- linux 下ab压力测试
1.ab的简介 ab是apachebench命令的缩写. ab是apache自带的压力测试工具.ab非常实用,它不仅可以对apache服务器进行网站访问压力测试,也可以对或其它类型的服务器进行压力测试 ...
- spring多模块项目手动整合
一.分别创建parent entity dao service controller web等模块项目,如图: 二.parent项目添加依赖 <!-- 集中定义依赖版本号 --> < ...
- 有这iconfont.woff文件 为什么还报404
解决方法1.打开服务器IIS管理器,找到MIME类型. 2.添加MIME类型 添加三条: 文件扩展名 MIME类型 .svg image/svg+xml.woff application/x-font ...
- call(),apply(),bind()区别?
每个函数都包含两个非继承而来的方法,apply()和call(),这两方法的用途都是在特定的作用域中调用函数,实际上等于设置函数数体内的this对象的值. apply()和call()第一个参数都一样 ...
- PHP——秒数转换为时分秒
前言 通讯记录需要用到的一个方法,就是将秒转为时分秒 方法 PHP有内置的方法,直接用即可,不过这个只是24小时以内.对于通讯录来说是够用了~ 示例 $v = 30; gmdate('H:i:s', ...
- 使用 mysqltuner 检测 mysql 稳定性
github : https://github.com/major/MySQLTuner-perl MySQLTuner是一个用Perl编写的脚本,它可以帮助您进行MySQL配置,并提出增强性能和稳定 ...