热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

python面向对象的特征_python面向对象的三大特性

继承继承是一种创建新类的方式,在python中,新建的类可以继承一个或多个父类,父类又可称为基类或超类,新建的类称为派生类

继承

继承是一种创建新类的方式,在python中,新建的类可以继承一个或多个父类,父类又可称为基类或超类,新建的类称为派生类或子类。

class A():pass #父类,基类,超类

class B:pass #父类,基类,超类

class C(A,B):pass #子类,派生类

class D(A):pass #子类,派生类

# 一个类 可以被多个类继承

# 一个类 可以继承多个父类——python里

__bases__查看所有继承的父类

__bases__则是查看所有继承的父类

print(A.__bases__)

(,)print(C.__bases__)

(, )

python3 只存在新式类

没有继承父类时默认继承object,object是所有python类的基类,它提供了一些常见方法(如__str__)的实现。

继承与抽象(先抽象再继承)

抽象即抽取类似或者说比较像的部分。

抽象分成两个层次:

1.将奥巴马和梅西这俩对象比较像的部分抽取成类;

2.将人,猪,狗这三个类比较像的部分抽取成父类。

抽象最主要的作用是划分类别(可以隔离关注点,降低复杂度)

1299848-20180118204444521-1499061105.png

继承:是基于抽象的结果,通过编程语言去实现它,肯定是先经历抽象这个过程,才能通过继承的方式去表达出抽象的结构。

(子类 是 父类)

抽象只是分析和设计的过程中,一个动作或者说一种技巧,通过抽象可以得到类。

1299848-20180118204624662-1149390516.png

函数名的重用

classAnimal:def __init__(self,name,aggr,hp):

self.name=name

self.aggr=aggr

self.hp=hp

self.func()deffunc(self):print(123)#classDog(Animal):deffunc(self):print(456)defbite(self,person):

person.hp-=self.aggr

d=Dog()#--> 456

只要是子类的对象调用,子类中有的名字 一定用子类的

在子类中,新建的重名的函数属性,在编辑函数内功能的时候,有可能需要重用父类中重名的那个函数功能,应该是用调用普通函数的方式,

即:类名.func(),此时就与调用普通函数无异了,因此即便是self参数也要为其传值.

classAnimal:def __init__(self,name,aggr,hp):

self.name=name

self.aggr=aggr

self.hp=hpdefeat(self):print('吃药回血')

self.hp+=100

classDog(Animal):def __init__(self,name,aggr,hp,kind):

Animal.__init__(self,name,aggr,hp) # self.kind = kind #派生属性

defeat(self):

Animal.eat(self)#如果既想实现新的功能也想使用父类原本的功能,还需要在子类中再调用父类

self.teeth = 2

def bite(self,person): #派生方法

person.hp -= self.aggr

在python3中,子类执行父类的方法也可以直接用super方法.(super只在python中存在)

classDog(Animal):def __init__(self,name,aggr,hp,kind):

super().__init__(name,aggr,hp) #只在新式类中有,python3中所有类都是新式类

#super(Animal,self).__init__(name,aggr,hp)

#Animal.eat(self)

self.kind = kind #派生属性

def eat(self):print('dog eating')

jin= Dog('金老板',200,500,'teddy')print(jin.name)

jin.eat()

super(Dog,jin).eat()

小结

父类中没有的属性 在子类中出现 叫做派生属性

父类中没有的方法 在子类中出现 叫做派生方法

只要是子类的对象调用,子类中有的名字 一定用子类的,子类中没有才找父类的,如果父类也没有报错#如果父类、子类都有,用子类的。

#如果还想用父类的,单独调用父类的:

#父类名.方法名 需要自己传self参数

#super().方法名 不需要自己传self

正常的代码中 单继承 ===减少了代码的重复

继承表达的是一种 子类 是 父类的关系

多继承

单继承 : 子类有的用子类 ,子类没有用父类。

多继承中,我们子类的对象调用一个方法,默认是就近原则,找的顺序是什么?

classF:def func(self): print('F')class A(F):pass

#def func(self): print('A')

classB(A):pass

#def func(self): print('B')

class E(F):pass

#def func(self): print('E')

classC(E):pass

#def func(self): print('C')

classD(B,C):pass

#def func(self):print('D')

d=D()#d.func()

python2.7 新式类和经典类共存,新式类要继承object

python3 只有新式类,默认继承object

经典类中 ,深度优先

新式类中 ,广度优先

经典类和新式类还有一个区别 mro方法只在新式类中存在

super 只在python3中存在

super的本质 :不是单纯找父类 而是根据调用者的节点位置的广度优先顺序来的

classA(object):def func(self): print('A')classB(A):deffunc(self):

super().func()print('B')classC(A):deffunc(self):

super().func()print('C')classD(B,C):deffunc(self):

super().func()print('D')

b=D()

b.func()print(B.mro())#[, , ]

钻石问题

1299848-20180118210127568-1212847479.png

1299848-20180118210258521-941080184.png

1299848-20180118210524959-641186526.png

新式类 : 顺序如图所示,以根节点D为依据,在保证每个类里的函数都能取到的基础上,广度优先。

经典类:深度优先 图1 B->A   图2 dbafce(不再走f,因为之前走过)   图3 dbace

小结

继承 : 什么是什么的关系(子类是父类)

单继承*****先抽象再继承,几个类之间的相同代码抽象出来,成为父类

子类自己没有的名字,就可以使用父类的方法和属性

如果子类自己有,一定是先用自己的

在类中使用self的时候,一定要看清楚self指向谁

多继承***新式类和经典类:

多继承寻找名字的顺序 : 新式类广度优先,经典类深度优先

新式类中 有一个类名.mro方法,查看广度优先的继承顺序

python3中 有一个super方法,根据广度优先的继承顺序查找上一个类

抽象类和接口类

java : 面向对象编程

设计模式 —— 接口

接口类 : python原生不支持(只是一种思想)

抽象类 : python原生支持的

classWechat(Payment):

def pay(self,money):

print('已经用微信支付了%s元'%money)classAlipay(Payment):

def pay(self,money):

print('已经用支付宝支付了%s元' %money)classApplepay(Payment):

def pay(self,money):

print('已经用applepay支付了%s元' %money)

def pay(pay_obj,money): # 统一支付入口

pay_obj.pay(money)

w=Wechat()

ap=Apple()

# a= Ali() #TypeError: Can't instantiate abstract class Ali with abstract methods pay

# pay(w,100) #微信支付了100

# pay(ap,100) #苹果支付了100

# pay(a,100)

p= Payment() #Can't instantiate abstract class Payment with abstract methods pay 不能创建

接口类的多继承问题

接口隔离原则

使用多个专门(Fly_Animal、Walk_Animal等)的接口,而不使用单一(Animal)的总接口。即客户端不应该依赖那些不需要的接口。

ContractedBlock.gif

ExpandedBlockStart.gif

fromabc import abstractmethod,ABCMetaclass Swim_Animal(metaclass=ABCMeta):

@abstractmethod

def swim(self):passclass Walk_Animal(metaclass=ABCMeta):

@abstractmethod

def walk(self):passclass Fly_Animal(metaclass=ABCMeta):

@abstractmethod

def fly(self):passclassTiger(Walk_Animal,Swim_Animal):

def walk(self):

pass

def swim(self):

passclassOldYing(Fly_Animal,Walk_Animal):passclass Swan(Swim_Animal,Walk_Animal,Fly_Animal):pass

View Code

抽象类 :

规范

一般情况下 单继承 能实现的功能都是一样的,所以在父类中可以有一些简单的基础实现

多继承的情况 由于功能比较复杂,所以不容易抽象出相同的功能的具体实现写在父类中

抽象类还是接口类 : 面向对象的开发规范 所有的接口类和抽象类都不能实例化

java :

java里的所有类的继承都是单继承,所以抽象类完美的解决了单继承需求中的规范问题

但对于多继承的需求,由于java本身语法的不支持,所以创建了接口Interface这个概念来解决多继承的规范问题

python

python中没有接口类 :

python中自带多继承 所以我们直接用class来实现了接口类

python中支持抽象类 : 一般情况下 单继承 不能实例化

且可以实现python代码

ContractedBlock.gif

ExpandedBlockStart.gif

#一切皆文件

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

class All_file(metaclass=abc.ABCMeta):

all_type='file'@abc.abstractmethod#定义抽象方法,无需实现功能

defread(self):'子类必须定义读功能'with open('filaname') as f:pass@abc.abstractmethod#定义抽象方法,无需实现功能

defwrite(self):'子类必须定义写功能'

pass

class Txt(All_file): #子类继承抽象类,但是必须定义read和write方法

defread(self):print('文本数据的读取方法')defwrite(self):print('文本数据的读取方法')class Sata(All_file): #子类继承抽象类,但是必须定义read和write方法

defread(self):print('硬盘数据的读取方法')defwrite(self):print('硬盘数据的读取方法')class Process(All_file): #子类继承抽象类,但是必须定义read和write方法

defread(self):print('进程数据的读取方法')defwrite(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)

View Code

什么是多态

多态 python 天生支持多态,python 动态强类型的语言

鸭子类型

不崇尚根据继承所得来的相似

我只是自己实现我自己的代码就可以了。

如果两个类刚好相似,并不产生父类的子类的兄弟关系,而是鸭子类型

list tuple 这种相似,是自己写代码的时候约束的,而不是通过父类约束的

classList():def __len__(self):pass

classTuple():def __len__(self):pass

deflen(obj):return obj.__len__()

l=Tuple()

len(l)

优点 : 松耦合 每个相似的类之间都没有影响

缺点 : 太随意了,只能靠自觉

封装

广义上面向对象的封装 :代码的保护,面向对象的思想本身就是一种

只让自己的对象能调用自己类中的方法

狭义上的封装 —— 面向对象的三大特性之一

属性 和 方法都藏起来 不让你看见

classPerson:__key = 123 #私有静态属性

def __init__(self,name,passwd):

self.name=name

self.__passwd = passwd #私有属性

def __get_pwd(self): #私有方法

return self.__passwd #只要在类的内部使用私有属性,就会自动的带上_类名

def login(self): #正常的方法调用私有的方法

self.__get_pwd()

alex= Person('alex','alex3714')print(alex._Person__passwd) #_类名__属性名

print(alex.get_pwd())

所有的私有 都是在变量的左边加上双下划綫

对象的私有属性

类中的私有方法

类中的静态私有属性

所有的私有的 都不能在类的外部使用(自觉_person)

classRoom:def __init__(self,name,length,width):

self.__name =name

self.__length =length

self.__width =widthdefget_name(self):return self.__name

defset_name(self,newName):if type(newName) is str and newName.isdigit() ==False:

self.__name =newNameelse:print('不合法的姓名')defarea(self):return self.__length * self.__widthjin= Room('金老板',2,1)print(jin.area())

jin.set_name('2')print(jin.get_name())#假设父类的私有属性 能被 子类调用么

classFoo:__key = '123' #_Foo__key

classSon(Foo):print(Foo.__key) #_Son__key 不能

#会用到私有的这个概念de场景#1.隐藏起一个属性 不想让类的外部调用#2.我想保护这个属性,不想让属性随意被改变#3.我想保护这个属性,不被子类继承

ContractedBlock.gif

ExpandedBlockStart.gif

接口类 抽象类

python中没有接口类,有抽象类,abc模块中的metaclass=ABCMeta,@abstructmethod

本质是做代码规范用的,希望在子类中实现和父类方法名字完全一样的方法

在java的角度上看 是有区别的

java本来就支持单继承 所以就有了抽象类

java没有多继承 所以为了接口隔离原则,设计了接口这个概念,支持多继承了

python及支持单继承也支持多继承,所以对于接口类和抽象类的区别就不那么明显了

甚至在python中没有内置接口类

多态和鸭子类型

多态 —— python天生支持多态

鸭子类型 —— 不依赖父类的情况下实现两个相似的类中的同名方法

封装 —— 私有的

在python中只要__名字

在python中只要__名字,就把这个名字私有化了

私有化了之后 就不能能从类的外部直接调用了

静态属性 方法 对象属性 都可以私有化

这种私有化只是从代码级别做了变形,并没有真的约束

变形机制 _类名__名字 在类外用这个调用,在类的内部直接__名字调用

小结

property

内置装饰器函数 只在面向对象中使用

#属性 查看 修改 删除

classPerson:def __init__(self,name):

self.__name =name

self.price= 20@propertydefname(self):return self.__name@name.deleterdefname(self):del self.__name@name.setterdefname(self,new_name):

self.__name =new_name

brother2= Person('二哥')#del Person.price

brother2.name = 'newName'brother2#del brother2.name

print(brother2.name)

method 方法

staticmathod 静态的方法 ***

classmethod 类方法 ****

类的操作行为classGoods:__discount = 0.8

def __init__(self,name,price):

self.name=name

self.__price =price

@propertydefprice(self):return self.__price * Goods.__discount@classmethod#把一个方法 变成一个类中的方法,这个方法就直接可以被类调用,不需要依托任何对象

def change_discount(cls,new_discount): #修改折扣

cls.__discount =new_discount

apple= Goods('苹果',5)print(apple.price)

Goods.change_discount(0.5) #Goods.change_discount(Goods)

print(apple.price)

当这个方法的操作只涉及静态属性的时候 就应该使用classmethod来装饰这个方法

# 在完全面向对象的程序中,

# 如果一个函数 既和对象没有关系 也和类没有关系 那么就用staticmethod将这个函数变成一个静态方法

classLogin:def __init__(self,name,password):

self.name=name

self.pwd=passworddef login(self):pass@staticmethoddef get_usr_pwd(): #静态方法

usr = input('用户名 :')

pwd= input('密码 :')

Login(usr,pwd)

Login.get_usr_pwd()

类方法和静态方法 都是类调用的。

对象可以调用类方法和静态方法,一般情况下 推荐用类名调用。

类方法 有一个默认参数 cls 代表这个类 cls

静态方法 没有默认的参数 就象函数一样



推荐阅读
author-avatar
義忠仁倫冧沫Bob
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有