博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
面向对象之封装与多态
阅读量:4663 次
发布时间:2019-06-09

本文共 4846 字,大约阅读时间需要 16 分钟。

一、多态

1.多态

多态指的是一类事物有多种形态

水有多种形态:冰 水雾 水

动物有多种形态:人,狗,猪

import abcclass Animal(metaclass=abc.ABCMeta): #同一类事物:动物    @abc.abstractmethod    def talk(self):        passclass 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 abcclass File(metaclass=abc.ABCMeta): #同一类事物:文件    @abc.abstractmethod    def click(self):        passclass Text(File): #文件的形态之一:文本文件    def click(self):        print('open file')class ExeFile(File): #文件的形态之二:可执行文件    def click(self):        print('execute file')文件
文件

2.多态性

多态性是指在不考虑实例类型的情况下使用实例

在面向对象方法中一般是这样表述多态性:

向不同的对象发送同一条消息,不同的对象在接收时会产生不同的行为(即方法)。也就是说,每个对象可以用自己的方式去响应共同的消息。所谓消息,就是调用函数,不同的行为就是指不同的实现,即执行不同的函数。

比如:老师.下课铃响了(),学生.下课铃响了(),老师执行的是下班操作,学生执行的是放学操作,虽然二者消息一样,但是执行的效果不同

peo=People()dog=Dog()pig=Pig()#peo、dog、pig都是动物,只要是动物肯定有talk方法#于是我们可以不用考虑它们三者的具体是什么类型,而直接使用peo.talk()dog.talk()pig.talk()#更进一步,我们可以定义一个统一的接口来使用def func(obj):    obj.talk()多态性
多态性

3、鸭子类型

Python崇尚鸭子类型,即‘如果看起来像、叫声像而且走起路来像鸭子,那么它就是鸭子’python程序员通常根据这种行为来编写程序。例如,如果想编写现有对象的自定义版本,可以继承该对象也可以创建一个外观和行为像,但与它无任何关系的全新对象,后者通常用于保存程序组件的松耦合度。

例1:利用标准库中定义的各种‘与文件类似’的对象,尽管这些对象的工作方式像文件,但他们没有继承内置文件对象的方法

二、封装

封装:隐藏对象的属性和实现细节,仅对外提供公共访问方式。

好处:

1、 将变化隔离; 

2.、便于使用;

3.、提高复用性; 

4.、提高安全性;

封装原则:

1、 将不需要对外提供的内容都隐藏起来;

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,即双下滑线开头的属性在继承给子类时,子类是无法覆盖的。

注意:

这种机制也并没有真正意义上限制我们从外部直接访问属性,知道了类名和属性名就可以拼出名字:_类名__属性,然后就可以访问了,如a._A__N

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定义成私有的,即__faclass A:     def __fa(self): #在定义时就变形为_A__fa         print('from A')     def test(self):         self.__fa() #只会与自己所在的类为准,即调用_A__fa class B(A):     def __fa(self): #在定义时就变形为_B__fa         print('from B') b=B()b.test()#from A私有方法
私有方法

3、扩展性

封装在于明确区分内外,使得类实现者可以修改封装内的东西而不影响外部调用者的代码;而外部使用用者只知道一个接口(函数),只要接口(函数)名、参数不变,使用者的代码永远无需改变。

4、property属性

'''例一:BMI指数(bmi是计算而来的,但很明显它听起来像是一个属性而非方法,如果我们将其做成一个属性,更便于理解)成人的BMI数值:过轻:低于18.5正常:18.5-23.9过重:24-27肥胖:28-32非常肥胖, 高于32  体质指数(BMI)=体重(kg)÷身高^2(m)  EX:70kg÷(1.75×1.75)=22.86'''class People:    def __init__(self,name,weight,height):        self.name=name        self.weight=weight        self.height=height    @property    def bmi(self):        return self.weight / (self.height**2)p1=People('egon',75,1.85)print(p1.bmi)BMI指数
import mathclass Circle:    def __init__(self,radius): #圆的半径radius        self.radius=radius    @property    def area(self):        return math.pi * self.radius**2 #计算面积    @property    def perimeter(self):        return 2*math.pi*self.radius #计算周长c=Circle(10)print(c.radius)print(c.area) #可以像访问数据属性一样去访问area,会触发一个函数的执行,动态计算出一个值print(c.perimeter) #同上'''输出结果:314.159265358979362.83185307179586'''#注意:此时的特性area和perimeter不能被赋值c.area=3 #为特性area赋值'''抛出异常:AttributeError: can't set attribute'''圆的周长和面积
圆的周长和面积

将一个类的函数定义成特性以后,对象再去使用的时候obj.name,根本无法察觉自己的name是执行了一个函数然后计算出来的,这种特性的使用方式遵循了统一访问的原则

5、setter,deleter

class A:    def __init__(self):        self.__x = 10    #返回__x的值    @property    def x(self):        return self.__x    #修改__x的值    @x.setter    def x(self,new_x):        self.__x = new_x    #删除__x的值    @x.deleter    def x(self):        del self.__xa = A()print(a.x)a.x = 20print(a.x)del a.xprint(a.x)私有属性的查看修改删除
私有属性的查看修改删除

6、classmethod,staticmethod

class Student:    f = open('student', encoding='utf-8')    def __init__(self):        pass    def func(self):        pass    @classmethod   #类方法:默认参数cls,可以直接用类名调用,可以与类属性交互    def show_student_info_class(cls):        for line in cls.f:            name, sex = line.strip().split(',')            print(name, sex)    @staticmethod   #静态方法  : 让类里的方法直接被类调用,就像正常的函数一样    def show_student_info_static():        f = open('student', encoding='utf-8')        for line in f:            name, sex = line.strip().split(',')            print(name, sex)Student.show_student_info_class()Student.show_student_info_static()类方法和静态方法
类方法和静态方法
海宝,男海博,女海娇,男海燕,女海东,男海峰,男
student文件

相同:都可以直接被类调用,不需要实例化

不同:类方法必须有一个cls参数表示这个类,可以使用类属性;静态方法不需要,静态方法不能直接使用

普通方法 默认有一个self对象传进来,并且只能被对象调用——绑定到对象

类方法 默认有一个cls传进来表示本类,并且可以被类和对象(不推荐)调用——绑定到类

静态方法 没有默认参数,并且可以被类和对象(不推荐)调用——非绑定

 

转载于:https://www.cnblogs.com/moning/p/7382611.html

你可能感兴趣的文章
NLP-训练个model出来写诗
查看>>
小小知识点(八)——星座图与PSK、QAM调制的关系
查看>>
LeetCode 235. Lowest Common Ancestor of a Binary Search Tree
查看>>
JAVA高级特性反射和注解
查看>>
spring boot properties文件与yaml文件的区别
查看>>
不错的博客
查看>>
左右固定,中间自适应的三栏式布局五种写法
查看>>
存一些可能会用得到的vue的UI框架
查看>>
MySql随笔part4 数据操作
查看>>
WPF MultiDataTrigger
查看>>
(CSDN迁移)js中的判空
查看>>
centos7上安装mysql说明
查看>>
Redis几个认识误区
查看>>
SQL Server 2008系统信息查询常用命令 查看表大小、记录数等
查看>>
Python学习 :常用模块(一)
查看>>
DirectFB 之 实例图像不断右移
查看>>
About The User Guide
查看>>
测试随笔
查看>>
20145324王嘉澜《网络对抗技术》 信息搜集与漏洞扫描
查看>>
[bzoj4849][Neerc2016]Mole Tunnels
查看>>