python 面向对象的三大特性
1.继承与派生
1,继承,和组合有点像,都是一个类中调用另一个类,但是组合是将一个类的对象变为另一个类的属性,而继承是将一个类的所有方法都给一个子类调用
class Animal: #父级 def __init__(self,name,hp,ad): self.name = name # 对象属性 属性 self.hp = hp #血量 self.ad = ad #攻击力 def eat(self): print('2233333') class Person(Animal): #子级 def __init__(self,name,hp,ad,sex): # Animal.__init__(self,name,hp,ad) super(Person, self).__init__(name,hp,ad) #在单继承中,super负责找到当前类所在的父类,在这个时候不需要手动传self self.sex = sex # 派生属性 def attack(self,dog): # 派生方法 print("%s攻击了%s"%(self.name,dog.name)) def eat(self): #重写 super().eat() #在类内部中调用super方法,找父类 print('66666') class Dog(Animal):#子级 def __init__(self, name, hp, ad, kind): Animal.__init__(self, name, hp, ad) self.kind = kind #派生属性 def bite(self,person): # 派生方法 print("%s咬了%s" % (self.name, person.name)) # 人 sex100 alex = Person('alex',100,10,'female') # 实例化 print(alex.__dict__) cheng = Dog('chen',100,10,'taidi') print(cheng.__dict__)
Animal是Person和Dog的父类,将方法继承给了他们,并且子类都可以利用直接调用和super两种方法调用父类的方法,注意super是在子类中有和父类同名的方法时候,并且想要调用父类的方法时候使用的。
单继承:多各类继承同一个类。
目的:多个类中有重复的方法,于是整合他们单独建立一个类,让他们都能调用
应用面:只要有重复方法,就可以被调用,但是需要注意的是对象的作用空间调取问题
关于对象的细节:1.在对象的使用情况下,对象都会先调用自身内部空间的属性,没有的情况下去找自己的类中的属性和方法,
再没有才会去寻找父级中的属性和方法。
2.对象的self是属于对象的即使传导到父类中也还是对象的self,所有返回的数据会出现在对象的空间里
单继承中的super:在单继承中super代表着调用父级的方法,基本格式super(默认,父级名,self).方法名()
多继承:一个类继承多个类
钻石继承:钻石继承是继承多个类的,利用广度优先算法所形成的的类似钻石的图形轨迹,所以称为钻石继承
版本问题:python2.x中多继承出现了两种算法,没有继承object的类叫做经典类,继承object的是新式类
经典类利用的是深度算法,直接读取到最底层在回来读取
新式类利用的是广度算法,只有读完所有的非最底层支点才会再去读取最后一层。
mro方法:在继承中可以使用mro方法查询继承的读取顺序,python2.x无法使用
class A: def funv(self): print('S') class B(A): def funv(self): print('b') class C(A): def funv(self): print('ni') class D(B,C): def funv(self): print('D') f = D() f.funv() print (D.mro())#查询有顺序 单继承则是继承的父级只有一位,多继承是多个父级继承给同一个类! super()在多继承中不是找父类,是根据子节点所在图的 mro顺序寻找下一个类 也就是遵循广度优先算法,寻找广度 在单继承中单纯的寻找父类 画图理解!!!
2,派生,从上面的例子可以看出除了继承外还有一种叫做派生,派生分为两种,一种是派生属性,一种是派生方法,
派生属性:单独属于这个类的属性。
派生方法:单独属于这个类的方法。
3,空间问题,在继承中,对象会先从对象的空间中查找属性,在没有的情况下调用类中的方法,再没有才会去父类中寻找。
4,object类
所有类的创建都需要完成下面步骤
1,创建一个空对象
2,调用init方法 ------即使没有继承关系,python默认继承object,并且调用调在object类中的init类
3,将初始化之后的对象返回调用chu
2.多态:
多态需要注意的是关于面向对象的设计原则,是由java发展演变而来,现有三种基本设计原则,
1.开放封闭原则 于装饰器有关:
开放是给拓展开放 :可以再源代码的基础上增加功能而不能对源代码进行修改
封闭是给修改封闭:不能对源代码进行修改
2.依赖倒置原则
重点:高层模块不应该依赖低层模块,二者都应该依赖其抽象;抽象不应该应该依赖细节;细节应该依赖抽象。换言之,要针对接口编程,而不是针对实现编程
3.接口隔离原则
接口提取了一群类共同的函数,可以把接口当做一个函数的集合。 然后让子类去实现接口中的函数。 这么做的意义在于归一化,什么叫归一化,就是只要是基于同一个接口实现的类,那么所有的这些类产生的对象在使用时,从用法上来说都一样。
归一化,让使用者无需关心对象的类是什么,只需要的知道这些对象都具备某些功能就可以了,这极大地降低了使用者的使用难度。
from abc import ABCMeta,abstractmethod #引用abc模块 规范方法 class Payment(metaclass=ABCMeta): @abstractmethod #装饰 def fuqian(self):pass class Alipay(Payment): #继承 def fuqian(self,money): print('支付宝支付成功%s'% money) class QQpay(Payment): def fuqian(self,money): print('qq支付成功%s' % money) def pay(obj,money): obj.fuqian(money) q = QQpay() a = Alipay() pay(a,233) pay(q,666) ##此为单继承,在java中由于没有多继承将会在最初设计一个规范类!后续的类都继承此规范,然后才能使用归一化
4,多态
多态和鸭子类型 多态一定通过继承实现 在java中所谓多态在一个类之下发展出来的多个类的对象都可以作为参数传入一个函数或者方法 在python中不需要刻意实现多态,因为python本身自带多态效果
鸭子类型 不是通过具体的继承关系来约束某些类中必须有哪些方法 是通过一种约定俗成的概念来保证在多个类中相似的功能叫做相同的名字
鸭子类型 class QQpay(): def pay(self,money): print('使用qq支付了%s元'%money) class Wechatpay(): def pay(self,money): print('使用微信支付了%s元'%money) def pay(pay_obj,money): pay_obj.pay(money)
3.封装
1.封装的概念:隐藏对象的属性和实现细节,仅对外提供公共访问方式。
广义:将代码装到一个容器里面。
狭义:给予每一种现象一个特定的名称。
2.私有化就是一种封装:
目的:将方法或者属性变为私有,使得不能被外部调用和继承。
class A:
__k = 2333 def __func(self): #双下滑线就是标志方法或者属性变为私有化 print('233333')
print(A.__k)#程序报错! AttributeError: type object 'A' has no attribute '__k'
print(A.__dict__)#结果:{'_A__k': 2333, '__module__': '__main__', '__doc__': None, '__dict__': <attribute '__dict__' of 'A' objects>, '__weakref__': <attribute '__weakref__' of 'A' objects>, '_A__func': <function A.__func at 0x0000000000D8E268>}
dict中有一个‘_A__k’ 就是私有化后发生了变形所产生的结果。
#试试继承吧!!!!!!!!!!1
私有化的特性: 1,当私有化后,在类外部不能直接调用,不论是属性还是方法,
2,遇到私有化的格式会在类的空间中将私有名变为 _类名__属性名/方法名
3.继承的时候,当不想要子类继承时候,利用私有化,子类将不会继承私有化的方法和属性
三个装饰器的使用:1,property:将类的方法伪装成属性
1.property和setter配合使用修改属性
2.property和delter配合使用删除属性或方法
2,classmethod:类方法”装饰后可将类名当做第一个参数的给予方法,从而在方法中调用类,并且不用实例化就能使用
3.startmethod:讲方法定义为公用方法,可以再外部当做函数调用,静态方法
将方法伪装成属性,方法中一般涉及的都是一些计算过程 from math import pi class Ring: def __init__(self,r): self.r = r @property def area(self): return self.r ** 2 * pi @property def long(self): return self.r * 2 * pi a = Ring(3) print(a.area) #直接调用 print(a.long) property和setter配合使用 class Person: def __init__(self,name,age): self.__name = name self.__age = age @property def name(self): return self.__name @name.setter def name(self,new_name): if type(new_name) == type(''): self.__name = new_name else: print('和输入有误') a = Person('233',999) print(a.name) a.name = 'alex' #请注意务必使用等于号!!!!!!!!!! print(a.name)
以下是配合删除deleter使用
#删除方法! class Person: def __init__(self,name,age): self.__name = name self.__age = age @property def name(self): return self.__name @name.deleter def name(self): del self.__name a = Person('233',999) a.name print(a.name) del a.name print(a.name)
总和一下,三种方法一起使用
class Goods: __ZK = 0.8 def __init__(self,name,price): self.name =name self.__price = price @property def Price(self): return self.__price * Goods.__ZK @Price.setter def Price(self,new_price): if type(new_price) is int or type(new_price)is float: self.__price = new_price else: print('233idjsad3') @classmethod def zk(cls,new_ZK): cls.__ZK = new_ZK @staticmethod def func(): print('韩家豪傻逼!') def func2(): print('韩家豪还是傻逼!') func2() Goods.zk(0.4) a = Goods('apple',5) print(a.Price) a.Price = 9 print(a.Price) Goods.func() a.func()