python基础(25):面向对象三大特性二(多态、封装)
1. 多态
1.1 什么是多态
多态指的是一类事物有多种形态。
动物有多种形态:人,狗,猪。
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')
文件有多种形态:文本文件,可执行文件。
import abc
class File(metaclass=abc.ABCMeta): #同一类事物:文件
@abc.abstractmethod
def click(self):
pass class Text(File): #文件的形态之一:文本文件
def click(self):
print('open file') class ExeFile(File): #文件的形态之二:可执行文件
def click(self):
print('execute file')
1.2 多态性
什么是多态动态绑定(在继承的背景下使用时,有时也称为多态性)。
多态性是指在不考虑实例类型的情况下使用实例:
在面向对象方法中一般是这样表述多态性:
向不同的对象发送同一条消息(!!!obj.func():是调用了obj的方法func,又称为向obj发送了一条消息func),不同的对象在接收时会产生不同的行为(即方法)。
也就是说,每个对象可以用自己的方式去响应共同的消息。所谓消息,就是调用函数,不同的行为就是指不同的实现,即执行不同的函数。比如:老师.下课铃响了(),学生.下课铃响了(),老师执行的是下班操作,学生执行的是放学操作,虽然二者消息一样,但是执行的效果不同。
peo=People()
dog=Dog()
pig=Pig() #peo、dog、pig都是动物,只要是动物肯定有talk方法
#于是我们可以不用考虑它们三者的具体是什么类型,而直接使用
peo.talk()
dog.talk()
pig.talk() #更进一步,我们可以定义一个统一的接口来使用
def func(obj):
obj.talk()
2. 封装
2.1 什么叫封装
隐藏对象的属性和实现细节,仅对外提供公共访问方式。
好处:
1. 将变化隔离;
2. 便于使用;
3. 提高复用性;
4. 提高安全性。
封装原则:
1. 将不需要对外提供的内容都隐藏起来;
2. 把属性都隐藏,提供公共方法对其访问。
2.2 私有变量和私有方法
在python中用双下划线开头的方式将属性隐藏起来(设置成私有的)
2.2.1 私有变量
#其实这仅仅这是一种变形操作
#类中所有双下划线开头的名称如__x都会自动变形成:_类名__x的形式: class A:
__N=0 #类的数据属性就应该是共享的,但是语法上是可以把类的数据属性设置成私有的如__N,会变形为_A__N
def __init__(self):
self.__X=10 #变形为self._A__X
def __foo(self): #变形为_A__foo
print('from A')
def bar(self):
self.__foo() #只有在类内部才可以通过__foo的形式访问到. #A._A__N是可以访问到的,即这种操作并不是严格意义上的限制外部访问,仅仅只是一种语法意义上的变形
这种自动变形的特点:
1.类中定义的__x只能在内部使用,如self.__x,引用的就是变形的结果。
2.这种变形其实正是针对外部的变形,在外部是无法通过__x这个名字访问到的。
3.在子类定义的__x不会覆盖在父类定义的__x,因为子类中变形成了:_子类名__x,而父类中变形成了:_父类名__x,即双下滑线开头的属性在继承给子类时,子类是无法覆盖的。
这种变形需要注意的问题是:
1.这种机制也并没有真正意义上限制我们从外部直接访问属性,知道了类名和属性名就可以拼出名字:_类名__属性,然后就可以访问了,如a._A__N
2.变形的过程只在类的内部生效,在定义后的赋值操作,不会变形
3.在继承中,父类如果不想让子类覆盖自己的方法,可以将方法定义为私有的
2.2.2 私有方法
#正常情况
>>> class A:
... def fa(self):
... print('from A')
... def test(self):
... self.fa()
...
>>> class B(A):
... def fa(self):
... print('from B')
...
>>> b=B()
>>> b.test()
from B #把fa定义成私有的,即__fa
>>> class A:
... def __fa(self): #在定义时就变形为_A__fa
... print('from A')
... def test(self):
... self.__fa() #只会与自己所在的类为准,即调用_A__fa
...
>>> class B(A):
... def __fa(self):
... print('from B')
...
>>> b=B()
>>> b.test()
from A
2.3 封装与扩展性
封装在于明确区分内外,使得类实现者可以修改封装内的东西而不影响外部调用者的代码;而外部使用用者只知道一个接口(函数),只要接口(函数)名、参数不变,使用者的代码永远无需改变。这就提供一个良好的合作基础——或者说,只要接口这个基础约定不变,则代码改变不足为虑。
#类的设计者
class Room:
def __init__(self,name,owner,width,length,high):
self.name=name
self.owner=owner
self.__width=width
self.__length=length
self.__high=high
def tell_area(self): #对外提供的接口,隐藏了内部的实现细节,此时我们想求的是面积
return self.__width * self.__length #使用者
>>> r1=Room('卧室','egon',20,20,20)
>>> r1.tell_area() #使用者调用接口tell_area #类的设计者,轻松的扩展了功能,而类的使用者完全不需要改变自己的代码
class Room:
def __init__(self,name,owner,width,length,high):
self.name=name
self.owner=owner
self.__width=width
self.__length=length
self.__high=high
def tell_area(self): #对外提供的接口,隐藏内部实现,此时我们想求的是体积,内部逻辑变了,只需求修该下列一行就可以很简答的实现,而且外部调用感知不到,仍然使用该方法,但是功能已经变了
return self.__width * self.__length * self.__high #对于仍然在使用tell_area接口的人来说,根本无需改动自己的代码,就可以用上新功能
>>> r1.tell_area()
2.4 property属性
什么是特性property?
将一个类的函数定义成特性以后,对象再去使用的时候obj.name,根本无法察觉自己的name是执行了一个函数然后计算出来的,这种特性的使用方式遵循了统一访问的原则。
除此之外,看下:
ps:面向对象的封装有三种方式:
【public】
这种其实就是不封装,是对外公开的
【protected】
这种封装方式对外不公开,但对朋友(friend)或者子类(形象的说法是“儿子”,但我不知道为什么大家 不说“女儿”,就像“parent”本来是“父母”的意思,但中文都是叫“父类”)公开
【private】
这种封装对谁都不公开
python并没有在语法上把它们三个内建到自己的class机制中,在C++里一般会将所有的所有的数据都设置为私有的,然后提供set和get方法(接口)去设置和获取,在python中通过property方法可以实现。
class Foo:
def __init__(self,val):
self.__NAME=val #将所有的数据属性都隐藏起来 @property
def name(self):
return self.__NAME #obj.name访问的是self.__NAME(这也是真实值的存放位置) @name.setter
def name(self,value):
if not isinstance(value,str): #在设定值之前进行类型检查
raise TypeError('%s must be str' %value)
self.__NAME=value #通过类型检查后,将值value存放到真实的位置self.__NAME @name.deleter
def name(self):
raise TypeError('Can not delete') f=Foo('egon')
print(f.name)
# f.name=10 #抛出异常'TypeError: 10 must be str'
del f.name #抛出异常'TypeError: Can not delete'
一个静态属性property本质就是实现了get,set,delete三种方法。
class Foo:
@property
def AAA(self):
print('get的时候运行我啊') @AAA.setter
def AAA(self,value):
print('set的时候运行我啊') @AAA.deleter
def AAA(self):
print('delete的时候运行我啊') #只有在属性AAA定义property后才能定义AAA.setter,AAA.deleter
f1=Foo()
f1.AAA
f1.AAA='aaa'
del f1.AAA
class Foo:
def get_AAA(self):
print('get的时候运行我啊') def set_AAA(self,value):
print('set的时候运行我啊') def delete_AAA(self):
print('delete的时候运行我啊')
AAA=property(get_AAA,set_AAA,delete_AAA) #内置property三个参数与get,set,delete一一对应 f1=Foo()
f1.AAA
f1.AAA='aaa'
del f1.AAA
怎么用?
class Goods: def __init__(self):
# 原价
self.original_price = 100
# 折扣
self.discount = 0.8 @property
def price(self):
# 实际价格 = 原价 * 折扣
new_price = self.original_price * self.discount
return new_price @price.setter
def price(self, value):
self.original_price = value @price.deleter
def price(self):
del self.original_price obj = Goods()
obj.price # 获取商品价格
obj.price = 200 # 修改商品原价
print(obj.price)
del obj.price # 删除商品原价
2.5 classmethod
class Classmethod_Demo():
role = 'dog' @classmethod
def func(cls):
print(cls.role) Classmethod_Demo.func()
2.6 staticmethod
class Staticmethod_Demo():
role = 'dog' @staticmethod
def func():
print("当普通方法用") Staticmethod_Demo.func()
python基础(25):面向对象三大特性二(多态、封装)的更多相关文章
- python基础(24):面向对象三大特性一(继承)
1. 继承 1.1 什么是继承 继承是一种创建新类的方式,在python中,新建的类可以继承一个或多个父类,父类又可称为基类或超类,新建的类称为派生类或子类. python中类的继承分为:单继承和多继 ...
- [.net 面向对象编程基础] (13) 面向对象三大特性——多态
[.net 面向对象编程基础] (13) 面向对象三大特性——多态 前面两节,我们了解了面向对象的的封装和继承特性,面向对象还有一大特性就是多态.比起前面的封装和继承,多态这个概念不是那么好理解.我们 ...
- [.net 面向对象编程基础] (11) 面向对象三大特性——封装
[.net 面向对象编程基础] (11) 面向对象三大特性——封装 我们的课题是面向对象编程,前面主要介绍了面向对象的基础知识,而从这里开始才是面向对象的核心部分,即 面向对象的三大特性:封装.继承. ...
- [.net 面向对象编程基础] (12) 面向对象三大特性——继承
[.net 面向对象编程基础] (12) 面向对象三大特性——继承 上节我们说了面向对象的三大特性之一的封装,解决了将对同一对象所能操作的所有信息放在一起,实现统一对外调用,实现了同一对象的复用,降低 ...
- Python学习 :面向对象 -- 三大特性
面向对象的三大特性 一.封装 把数据.值.变量放入到对象中 构造方法 _init_方法 特殊作用: 在 obj = 类名() 执行时: 内部自动执行两个步骤: 1.创建对象 2.通过对象执行类中的一个 ...
- python学习-64 面向对象三大特性----继承1
面向对象三大特性 1.三大特性? 继承,多态,封装 2.什么是继承? 类的继承和现实生活中的父与子,继承关系是一样的,父类为基类. python中的类继承分为:单继承和多继承 3.举例说明 class ...
- 《Python》 面向对象三大特性之多态、封装
一.多态 1.什么是多态? 一个类表现出的多种状态:通过继承来实现的 在Java中的表现:在一个函数中需要给参数指定数据类型,如果这个地方可以接收两个以上类型的参数,那么这些类型应该有一个父类,这个父 ...
- python学习 day23 面向对象三大特性之继承
### 面向对象三大特性值继承#### 1.什么是继承 继承是一种关系,必须存在两个对象才可能产生这种关系,在现实生活中的继承,王思聪可以继承王健林的财产 被继承的成为父,继承的一方成为子 在程序中, ...
- Java中面向对象三大特性之——多态
多态的概述: 多态是继封装.继承之后,面向对象的第三大特性. 生活中,比如跑的动作,小猫.小狗和大象,跑起来是不一样的.再比如飞的动作,昆虫.鸟类和飞机,飞起来也是不一样的.可见,同一行为,通过不同 ...
随机推荐
- 三行Jquery代码实现简单的选项卡
今晚,我们来用实现一个简单的选项卡切换代码,主要代码只有两行. 效果: 思路:通过切换JQuery控制div的显隐和样式的改变 其中那个一个div显示,其余全隐藏 实现: <!DOCTYPE h ...
- 被忽略的CSS规则
说起CSS规则,除了普通规则(属性和值,key:value),可能大家都会想到@media,@keyframes,@fontface等常用的,那剩余的大家是否有所了解呢. 我们先来看一看CSS有哪些规 ...
- ubuntu16搭建文件服务器
这篇记录,如何在ubuntu16 安装 FastDFS 文件服务器,详细步骤 环境依赖 apt-get install make apt-get install unzip apt-get insta ...
- go源码解析-Println的故事
本文主要通过平常常用的go的一个函数,深入源码,了解其底层到底是如何实现的. Println Println函数接受参数a,其类型为-interface{}.用过Java的对这个应该比较熟悉,Java ...
- H5 App实现热更新,不需要重新安装app
直接上代码吧,你竟然搜到了我的文章就应该知道了,为什么要热更新 //app热更新下载 //假定字符串的每节数都在5位以下 function toNum(a) { //也可以这样写 var c=a.sp ...
- Go-包
Go-包 包的介绍以及使用 为什么使用包 为了更加好的维护代码 包的位置 必须再GOPATH路径的src中 能导入的内容 导入的内容名称必须是大写字母开头不然无法导入 包 src中的一个文件夹为一个包 ...
- Implement Property Value Validation in the Application Model 在应用程序模型中实现属性值验证
In this lesson, you will learn how to check whether or not a property value satisfies a particular r ...
- 松软科技前端课堂:JavaScript 数值方法
Number 方法帮助您处理数值. Number 方法和属性 原始值(比如 3.14 或 2016),无法拥有属性和方法(因为它们不是对象). 但是通过 JavaScript,方法和属性也可用于原始值 ...
- Java - IO 内存流和打印流
IO 内存流和打印流操作 字符编码 计算机中所有的信息组成都是二进制数据,所有能够描述的中文文字都是经过处理后的结果:所有的语言文字都会使用编码来进行描述,例如:ASCII码 常见编码 GBK/GB2 ...
- ODA: After Apply ODA 12.2.1.2.0 Patch, Unable to Create TableSpace Due to [ORA-15001: diskgroup "DATA" does not exist or is not mounted | ORA-15040: diskgroup is incomplete] (Doc ID 2375553.1)
ODA: After Apply ODA 12.2.1.2.0 Patch, Unable to Create TableSpace Due to [ORA-15001: diskgroup &quo ...