一、抽象类

  抽象类是一个特殊的类,它的特殊之处在于只能被继承,不能被实例化

1、在python中实现抽象类

import abc #利用abc模块实现抽象类

class All_file(metaclass=abc.ABCMeta):
all_type='file'
@abc.abstractmethod #定义抽象方法,无需实现功能
def read(self):
'子类必须定义读功能'
pass
@abc.abstractmethod #定义抽象方法,无需实现功能
def write(self):
'子类必须定义写功能'
pass # class Txt(All_file):
# pass
#
# t1=Txt() #报错,子类没有定义抽象方法 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('硬盘数据的读取方法') wenbenwenjian=Txt()
yingpanwenjian=Sata() #这样大家都是被归一化了,也就是一切皆文件的思想
wenbenwenjian.read()
yingpanwenjian.write()

2、抽象类与接口

  抽象类的本质还是类,指的是一组类的相似性,包括数据属性(如all_type)和函数属性(如read、write),而接口只强调函数属性的相似性。

  抽象类是一个介于类和接口直接的一个概念,同时具备类和接口的部分特性,可以用来实现归一化设计 

二、继承的实现原理(继承顺序)

1、在python中,如果类继承了多个类,那么其寻找的方式有两种:分别是:广度优先和深度优先

  当类是新式类是,多继承情况下,会按照广度优先方式查找

  当类是经典类是,多继承情况下,会按照深度优先方式查找

假如有A-H类的继承关系如下:

  

#新式类:
class A(object):
def test(self):
print('from A')
pass
class B(A):
# def test(self):
# print('from B')
pass
class C(A):
# def test(self):
# print('from C')
pass
class D(A):
# def test(self):
# print('from D')
pass
class E(B):
# def test(self):
# print('from E')
pass
class F(C):
# def test(self):
# print('from F')
pass
class G(D):
# def test(self):
# print('from G')
pass
class H(E,F,G):
# def test(self):
# print('from H')
pass
h=H()
# h.test=1
# print h.__dict__
#新式类的在这中继承结构下,属性的查找关系
# H->E->B->F->C-G-D-A 广度优先 #经典类的在这中继承结构下,属性的查找关系
# H-E-B-A-F-C-G-D 深度优先

 2、继承原理

   Python到底是如何实现继承的,对于你定义的每一个类,python会计算出一个方法解析顺序(MRO)列表,这个MRO列表就是一个简单的所有基类的线性顺序列表,例如

 >>> F.mro() #等同于F.__mro__
[<class '__main__.F'>, <class '__main__.D'>, <class '__main__.B'>, <class '__main__.E'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>]

  为了实现继承,python会在MRO列表上从左到右开始查找基类,直到找到第一个匹配这个属性的类为止。
  而这个MRO列表的构造是通过一个C3线性化算法来实现的。我们不去深究这个算法的数学原理,它实际上就是合并所有父类的MRO列表并遵循如下三条准则:

1.子类会先于父类被检查
2.多个父类会根据它们在列表中的顺序被检查
3.如果对下一个类存在两个合法的选择,选择第一个父类

3、子类中调用父类方法

有两种方法:

  1、People.__init__(self,name,age,sex)    #指名道姓地调用People类的__init__函数

  2、super().__init__(name,age,sex)           #调用父类的__init__的功能,实际上用的是绑定方法,super只查找一次

class People:
def __init__(self,name,age,sex):
self.name=name
self.age=age
self.sex=sex
def foo(self):
print('from parent') class Teacher(People):
def __init__(self,name,age,sex,salary,level):
# People.__init__(self,name,age,sex) #指名道姓地调用People类的__init__函数 #在python3中
super().__init__(name,age,sex) #调用父类的__init__的功能,实际上用的是绑定方法,super只查找一次
       self.salary=salary
self.level=level
def foo(self):
super().foo()
print('from child') t=Teacher('egon',18,'male',3000,10)
# print(t.name,t.age,t.sex,t.salary,t.level)
t.foo()

  

三、封装

1、封装不是单纯意义的隐藏:

  1:封装数据的主要原因是:保护隐私

  2:封装方法的主要原因是:隔离复杂度

2、封装分为两个层面

  1)第一个层面的封装(什么都不用做):创建类和对象会分别创建二者的名称空间,我们只能用类名.或者obj.的方式去访问里面的名字,这本身就是一种封装;对于这一层面的封装(隐藏),类名.和实例名.就是访问隐藏属性的接口

  2)第二个层面的封装:类中把某些属性和方法隐藏起来(或者说定义成私有的),只在类的内部使用、外部无法访问,或者留下少量接口(函数)供外部访问。    

    在python中用双下划线的方式实现隐藏属性(设置成私有的)

    类中所有双下划线开头的名称,如__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的形式访问到.,在类的外部,无法直接使用变形的属性 #在外部访问隐藏函数方式:
t=A()
t._A__foo()

这种自动变形的特点:

  1.类中定义的__x只能在内部使用,如self.__x,引用的就是变形的结果

  2.这种变形其实正是针对外部的变形,在外部是无法通过__x这个名字访问到的。

  3.在子类定义的__x不会覆盖在父类定义的__x,因为子类中变形成了:_子类名__x,而父类中变形成了:_父类名__x,即双下滑线开头的属性在继承给子类时,子类是无法覆盖的。

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

3、与property结合使用的封装

class People:
def __init__(self,name,age,sex,height,weight,permission=False):
self.__name=name
self.__age=age
self.__sex=sex
self.__height=height
self.__weight=weight
self.permission=permission @property #只读
def name(self):
return self.__name @name.setter #可写
def name(self,val):
if not isinstance(val,str):
raise TypeError('名字必须为字符串')
self.__name=val @name.deleter #可删除
def name(self):
if not self.permission:
raise PermissionError('权限不够')
del self.__name @property
def bmi(self):
return self.__weight/(self.__height**2) def tell_info(self):
print('''
--------%s info----------
Name:%s
Age:%s
Sex:%s
Height:%s
Weight:%s
--------------------------
'''%(self.__name,self.__name,self.__age,self.__sex,self.__height,self.__weight)) egon=People('egon',18,'male',1.76,72)
egon.tell_info()
print(egon.name)
egon.name='alex'
print(egon.name)
# egon.permission=True
# del egon.name
print(egon.bmi)

  

四、 多态与多态性

1、多态指的是一类事物有多种形态,(一个抽象类有多个子类,因而多态的概念依赖于继承)

  1. 序列类型有多种形态:字符串,列表,元组。

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

 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')

2、多态性是指具有不同功能的函数可以使用相同的函数名,这样就可以用一个函数名调用不同功能的函数。

  在面向对象方法中一般是这样表述多态性:向不同的对象发送同一条消息(!!!obj.func():是调用了obj的方法func,又称为向obj发送了一条消息func),不同的对象在接收时会产生不同的行为(即方法)。也就是说,每个对象可以用自己的方式去响应共同的消息。所谓消息,就是调用函数,不同的行为就是指不同的实现,即执行不同的函数。

 >>> def func(animal): #参数animal就是对态性的体现
... animal.talk()
...
>>> people1=People() #产生一个人的对象
>>> pig1=Pig() #产生一个猪的对象
>>> dog1=Dog() #产生一个狗的对象
>>> func(people1)
say hello
>>> func(pig1)
say aoao
>>> func(dog1)
say wangwang

3、多态性的好处

  1.增加了程序的灵活性

    以不变应万变,不论对象千变万化,使用者都是同一种形式去调用,如func(animal)

  2.增加了程序额可扩展性

    通过继承animal类创建了一个新的类,使用者无需更改自己的代码,还是用func(animal)去调用     

 >>> class Cat(Animal): #属于动物的另外一种形态:猫
... def talk(self):
... print('say miao')
...
>>> def func(animal): #对于使用者来说,自己的代码根本无需改动
... animal.talk()
...
>>> cat1=Cat() #实例出一只猫
>>> func(cat1) #甚至连调用方式也无需改变,就能调用猫的talk功能
say miao '''
这样我们新增了一个形态Cat,由Cat类产生的实例cat1,使用者可以在完全不需要修改自己代码的情况下。使用和人、狗、猪一样的方式调用cat1的talk方法,即func(cat1)
'''

四、 绑定方法

类中定义的函数分成两大类:

一:绑定方法(绑定给谁,谁来调用就自动将它本身当作第一个参数传入):

  1. 绑定到类的方法:用classmethod装饰器装饰的方法。 为类量身定制类.boud_method(),自动将类当作第一个参数传入(其实对象也可调用,但仍将类当作第一个参数传入)

  2. 绑定到对象的方法:没有被任何装饰器装饰的方法。为对象量身定制对象.boud_method(),自动将对象当作第一个参数传入

  (属于类的函数,类可以调用,但是必须按照函数的规则来,没有自动传值那么一说)

二:非绑定方法:用staticmethod装饰器装饰的方法

     1. 不与类或对象绑定,类和对象都可以调用,但是没有自动传值那么一说。就是一个普通工具而已

  注意:与绑定到对象方法区分开,在类中直接定义的函数,没有被任何装饰器装饰的,都是绑定到对象的方法,可不是普通函数,对象调用该方法会自动传值,而staticmethod装饰的方法,不管谁来调用,都没有自动传值一说

 

绑定方法:绑定给谁就是给谁用的

class People:
def __init__(self,name):
self.name=name
def bar(self):
print('--->',self.name) @classmethod
def func(cls):
print(cls)
f=People('egon') # print(People.func) #绑定给类
# print(f.bar) #绑定给对象的 # People.func()
# f.func()

2、 staticmethod:不与类或对象绑定,谁都可以调用,没有自动传值效果,python为我们内置了函数staticmethod来把类中的函数定义成静态方法

import hashlib
import time
class MySQL:
def __init__(self,host,port):
self.id=self.create_id()
self.host=host
self.port=port
@staticmethod
def create_id(): #就是一个普通工具
m=hashlib.md5(str(time.clock()).encode('utf-8'))
return m.hexdigest() print(MySQL.create_id) #<function MySQL.create_id at 0x0000000001E6B9D8> #查看结果为普通函数
conn=MySQL('127.0.0.1',3306)
print(conn.create_id) #<function MySQL.create_id at 0x00000000026FB9D8> #查看结果为普通函数

3、 classmethod:classmehtod是给类用的,即绑定到类,类在使用时会将类本身当做参数传给类方法的第一个参数(即便是对象来调用也会将类当作第一个参数传入),python为我们内置了函数classmethod来把类中的函数定义成类方法

HOST='127.0.0.1'
PORT=
DB_PATH=r'C:\Users\Administrator\PycharmProjects\test\面向对象编程\test1\db'

settings.py内容

import settings
import hashlib
import time
class MySQL:
def __init__(self,host,port):
self.host=host
self.port=port @classmethod
def from_conf(cls):
print(cls)
return cls(settings.HOST,settings.PORT) print(MySQL.from_conf) #<bound method MySQL.from_conf of <class '__main__.MySQL'>>
conn=MySQL.from_conf() print(conn.host,conn.port)
conn.from_conf() #对象也可以调用,但是默认传的第一个参数仍然是类

  

Python基础(17)_面向对象程序设计(抽象类、继承原理、封装、多态,绑定方法)的更多相关文章

  1. python基础——17(面向对象)

    一.名称空间 名称空间有内置名称空间,全局名称空间,局部名称空间.它是用来存放名字与值对应关系的地方. test.py文件: num = 10 def fn(): print("fn run ...

  2. C#基础总结之八面向对象知识点总结-继承与多态-接口

    .方法深入讲解(返回值,形参与实参) 方法 public int getName(int i,int j) { int sum = i + j; return sum; } .利用泛型存储对象数据 . ...

  3. 十七. Python基础(17)--正则表达式

    十七. Python基础(17)--正则表达式 1 ● 正则表达式 定义: Regular expressions are sets of symbols that you can use to cr ...

  4. Python基础(16)_面向对象程序设计(类、继承、派生、组合、接口)

    一.面向过程程序设计与面向对象程序设计 面向过程的程序设计:核心是过程,过程就解决问题的步骤,基于该思想设计程序就像是在设计一条流水线,是一种机械式的思维方式 优点:复杂的问题的简单化,流程化 缺点: ...

  5. Python基础(18)_面向对象程序设计2(反射、__str__、__del__、__item__系列)

    一 isinstance(obj,cls)和issubclass(sub,super) isinstance(obj,cls)检查是否obj是否是类 cls 的对象 class Foo(object) ...

  6. python基础学习Day17 面向对象的三大特性之继承、类与对象名称空间小试

    一.课前回顾 类:具有相同属性和方法的一类事物 实例化:类名() 过程: 开辟了一块内存空间 执行init方法 封装属性 自动的把self返回给实例化对象的地方 对象:实例 一个实实在在存在的实体 组 ...

  7. python基础17 ---继承补充知识

    一.继承的顺序 1.在python中的类可以集成多个类,既然是继承多个类就有类的寻找顺序这么一说.其寻找方法就有广度优先和深度优先两种. 2.当类是新式类,多继承的情况下会按照广度优先的顺序查找. 如 ...

  8. python基础语法15 面向对象2 继承,多态,继承json模块中JSONEncoder,并派生出新的功能

    继承 1.什么是继承? 继承是一种新建类的方式,新建的类称之为子类或派生类,继承的父类称之为基类或超类. - 在Python中,一个子类可以继承多个父类.(面试可能会问) - 在其它语言中,一个子类只 ...

  9. python基础整理4——面向对象装饰器惰性器及高级模块

    面向对象编程 面向过程:根据业务逻辑从上到下写代码 面向对象:将数据与函数绑定到一起,进行封装,这样能够更快速的开发程序,减少了重复代码的重写过程 面向对象编程(Object Oriented Pro ...

随机推荐

  1. 使用maven结合requirejs管理前端脚本

    已有的web项目,一直使用Maven做工程管理,现阶段前端调整为使用requirejs来负责模块加载依赖,同时使用jasmine来完成前端的UT. 便与在maven下统一管理,简单整理了下合在一起的使 ...

  2. awk 数组

    Arrays        Arrays are subscripted with an expression between square brackets ([ and ]).   If the ...

  3. std::copy ( myvector.begin(), myvector.end(), out_it )

    在实际生产环境中,不能进行调试,所以程序通常需要编译一个DEBUG版本来辅助我们找出问题所在,编译这样的DEBUG版本最常用的手段就是在关键处输出我们关心一些变量的值到屏幕. 如果输出的简单的变量值, ...

  4. Could not calculate build plan

    问题:根据你提供的镜像地址,下载相应的jar包失败 原因: 1.你提供的镜像地址不稳定,把settings.xml文件中的mirror改成稳定的镜像地址 2.网络不稳定,重新下载,或者切换网络.

  5. 更新换代----systemctl命令取代chkconfig和service

    systemctl命令是系统服务管理器指令,它实际上将 service 和 chkconfig 这两个命令组合到一起. 任务 旧指令 新指令 使某服务自动启动 chkconfig --level 3 ...

  6. 深度历险:Redis 内存模型详解

    https://mp.weixin.qq.com/s/Gp6Ur7omGY6ZqDWygU2meQ Redis 是目前最火爆的内存数据库之一,通过在内存中读写数据,大大提高了读写速度,可以说 Redi ...

  7. Java-文件上传和下载

    文件上传和下载的原理 设置将表单的两个属性的:method="post",enctype="multipart/form-data",让表单以二进制编码的方式提 ...

  8. Java基础 - 强引用、弱引用、软引用、虚引用

    1.强引用(StrongReference) 强引用是使用最普遍的引用. 假设一个对象具有强引用.那垃圾回收器绝不会回收它.例如以下: [java] view plaincopyprint" ...

  9. Laravel5.1 模型 --一对多关系

    一对多关系算是比较常用的一种关联关系了,关于一对多我们可以用 文章对应评论 来举例:一篇文章可以有多个评论,但是一个评论只属于一篇文章. 这就是一对多关系. 1 实现一对多关系 我们先来准备两个模型, ...

  10. Linux(Centos6.5)下安装svn服务器,并通过http访问

    linux安装svn其实很容易,个人觉得难就难在配置上,反复配置,琢磨,查找相关资料,总算是成功了.. 安装: 安装svn,一般情况下,选择yum方式安装还是比较简单的. ? 1 2 [root@mo ...