继承
继承是一种创建新类的方式,在python中,新建的类可以继承一个或多个父类,父类又可称为基类或超类,新建的类称为派生类或子类。
class A():pass # 父类,基类,超类 class B:pass # 父类,基类,超类 class C(A,B):pass # 子类,派生类 class D(A):pass # 子类,派生类
# 一个类 可以被多个类继承
# 一个类 可以继承多个父类——python里
__bases__查看所有继承的父类 __bases__则是查看所有继承的父类 print(A.__bases__) (<class 'object'>,) print(C.__bases__) (<class '__main__.A'>, <class '__main__.B'>)
python3 只存在新式类
没有继承父类时默认继承object,object是所有python类的基类,它提供了一些常见方法(如__str__)的实现。
继承与抽象(先抽象再继承)
抽象即抽取类似或者说比较像的部分。
抽象分成两个层次:
1.将奥巴马和梅西这俩对象比较像的部分抽取成类;
2.将人,猪,狗这三个类比较像的部分抽取成父类。
抽象最主要的作用是划分类别(可以隔离关注点,降低复杂度)
继承:是基于抽象的结果,通过编程语言去实现它,肯定是先经历抽象这个过程,才能通过继承的方式去表达出抽象的结构。
(子类 是 父类)
抽象只是分析和设计的过程中,一个动作或者说一种技巧,通过抽象可以得到类。
函数名的重用
class Animal: def __init__(self,name,aggr,hp): self.name = name self.aggr = aggr self.hp = hp self.func() def func(self): print(123) # class Dog(Animal): def func(self): print(456) def bite(self,person): person.hp -= self.aggr d = Dog() #--> 456 只要是子类的对象调用,子类中有的名字 一定用子类的
在子类中,新建的重名的函数属性,在编辑函数内功能的时候,有可能需要重用父类中重名的那个函数功能,应该是用调用普通函数的方式,
即:类名.func(),此时就与调用普通函数无异了,因此即便是self参数也要为其传值.
class Animal: def __init__(self,name,aggr,hp): self.name = name self.aggr = aggr self.hp = hp def eat(self): print('吃药回血') self.hp+=100 class Dog(Animal): def __init__(self,name,aggr,hp,kind): Animal.__init__(self,name,aggr,hp) # self.kind = kind # 派生属性
def eat(self): Animal.eat(self) # 如果既想实现新的功能也想使用父类原本的功能,还需要在子类中再调用父类 self.teeth = 2
def bite(self,person): # 派生方法 person.hp -= self.aggr
在python3中,子类执行父类的方法也可以直接用super方法.(super只在python中存在)
class Dog(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 正常的代码中 单继承 === 减少了代码的重复 继承表达的是一种 子类 是 父类的关系
多继承
单继承 : 子类有的用子类 ,子类没有用父类。
多继承中,我们子类的对象调用一个方法,默认是就近原则,找的顺序是什么?
class F: def func(self): print('F') class A(F):pass # def func(self): print('A') class B(A): pass # def func(self): print('B') class E(F):pass # def func(self): print('E') class C(E): pass # def func(self): print('C') class D(B,C): pass # def func(self):print('D') d = D() # d.func()
python2.7 新式类和经典类共存,新式类要继承object
python3 只有新式类,默认继承object
经典类中 ,深度优先
新式类中 ,广度优先
经典类和新式类还有一个区别 mro方法只在新式类中存在
super 只在python3中存在
super的本质 :不是单纯找父类 而是根据调用者的节点位置的广度优先顺序来的
class A(object): def func(self): print('A') class B(A): def func(self): super().func() print('B') class C(A): def func(self): super().func() print('C') class D(B,C): def func(self): super().func() print('D') b = D() b.func() print(B.mro())#[<class '__main__.B'>, <class '__main__.A'>, <class 'object'>]
钻石问题
新式类 : 顺序如图所示,以根节点D为依据,在保证每个类里的函数都能取到的基础上,广度优先。
经典类:深度优先 图1 B->A 图2 dbafce(不再走f,因为之前走过) 图3 dbace
小结
继承 : 什么是什么的关系(子类是父类) 单继承 ***** 先抽象再继承,几个类之间的相同代码抽象出来,成为父类 子类自己没有的名字,就可以使用父类的方法和属性 如果子类自己有,一定是先用自己的 在类中使用self的时候,一定要看清楚self指向谁 多继承 *** 新式类和经典类: 多继承寻找名字的顺序 : 新式类广度优先,经典类深度优先 新式类中 有一个类名.mro方法,查看广度优先的继承顺序 python3中 有一个super方法,根据广度优先的继承顺序查找上一个类
抽象类和接口类
java : 面向对象编程
设计模式 —— 接口
接口类 : python原生不支持(只是一种思想)
抽象类 : python原生支持的
class Wechat(Payment): def pay(self,money): print('已经用微信支付了%s元'%money) class Alipay(Payment): def pay(self,money): print('已经用支付宝支付了%s元' % money) class Applepay(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)的总接口。即客户端不应该依赖那些不需要的接口。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
from abc import abstractmethod,ABCMeta class Swim_Animal(metaclass=ABCMeta): @abstractmethod def swim(self):pass class Walk_Animal(metaclass=ABCMeta): @abstractmethod def walk(self):pass class Fly_Animal(metaclass=ABCMeta): @abstractmethod def fly(self):pass class Tiger(Walk_Animal,Swim_Animal): def walk(self): pass def swim(self): pass class OldYing(Fly_Animal,Walk_Animal):pass class Swan(Swim_Animal,Walk_Animal,Fly_Animal):pass
抽象类 :
规范
一般情况下 单继承 能实现的功能都是一样的,所以在父类中可以有一些简单的基础实现
多继承的情况 由于功能比较复杂,所以不容易抽象出相同的功能的具体实现写在父类中
抽象类还是接口类 : 面向对象的开发规范 所有的接口类和抽象类都不能实例化
java :
java里的所有类的继承都是单继承,所以抽象类完美的解决了单继承需求中的规范问题
但对于多继承的需求,由于java本身语法的不支持,所以创建了接口Interface这个概念来解决多继承的规范问题
python
python中没有接口类 :
python中自带多继承 所以我们直接用class来实现了接口类
python中支持抽象类 : 一般情况下 单继承 不能实例化
且可以实现python代码
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#一切皆文件 import abc #利用abc模块实现抽象类 class All_file(metaclass=abc.ABCMeta): all_type='file' @abc.abstractmethod #定义抽象方法,无需实现功能 def read(self): '子类必须定义读功能' with open('filaname') as f: pass @abc.abstractmethod #定义抽象方法,无需实现功能 def write(self): '子类必须定义写功能' pass 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('硬盘数据的读取方法') class Process(All_file): #子类继承抽象类,但是必须定义read和write方法 def read(self): print('进程数据的读取方法') def write(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)
什么是多态
多态 python 天生支持多态,python 动态强类型的语言
鸭子类型
不崇尚根据继承所得来的相似
我只是自己实现我自己的代码就可以了。
如果两个类刚好相似,并不产生父类的子类的兄弟关系,而是鸭子类型
list tuple 这种相似,是自己写代码的时候约束的,而不是通过父类约束的
class List(): def __len__(self):pass class Tuple(): def __len__(self):pass def len(obj): return obj.__len__() l = Tuple() len(l)
优点 : 松耦合 每个相似的类之间都没有影响
缺点 : 太随意了,只能靠自觉
封装
广义上面向对象的封装 :代码的保护,面向对象的思想本身就是一种
只让自己的对象能调用自己类中的方法
狭义上的封装 —— 面向对象的三大特性之一
属性 和 方法都藏起来 不让你看见
class Person: __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)
class Room: def __init__(self,name,length,width): self.__name = name self.__length = length self.__width = width def get_name(self): return self.__name def set_name(self,newName): if type(newName) is str and newName.isdigit() == False: self.__name = newName else: print('不合法的姓名') def area(self): return self.__length * self.__width jin = Room('金老板',2,1) print(jin.area()) jin.set_name('2') print(jin.get_name()) # 假设父类的私有属性 能被 子类调用么 class Foo: __key = '123' # _Foo__key class Son(Foo): print(Foo.__key) # _Son__key 不能 # 会用到私有的这个概念de场景 # 1.隐藏起一个属性 不想让类的外部调用 # 2.我想保护这个属性,不想让属性随意被改变 # 3.我想保护这个属性,不被子类继承
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
接口类 抽象类 python中没有接口类,有抽象类,abc模块中的metaclass = ABCMeta,@abstructmethod 本质是做代码规范用的,希望在子类中实现和父类方法名字完全一样的方法 在java的角度上看 是有区别的 java本来就支持单继承 所以就有了抽象类 java没有多继承 所以为了接口隔离原则,设计了接口这个概念,支持多继承了 python及支持单继承也支持多继承,所以对于接口类和抽象类的区别就不那么明显了 甚至在python中没有内置接口类 多态和鸭子类型 多态 —— python天生支持多态 鸭子类型 —— 不依赖父类的情况下实现两个相似的类中的同名方法 封装 —— 私有的 在python中只要__名字 在python中只要__名字,就把这个名字私有化了 私有化了之后 就不能能从类的外部直接调用了 静态属性 方法 对象属性 都可以私有化 这种私有化只是从代码级别做了变形,并没有真的约束 变形机制 _类名__名字 在类外用这个调用,在类的内部直接__名字调用
property
内置装饰器函数 只在面向对象中使用
# 属性 查看 修改 删除 class Person: def __init__(self,name): self.__name = name self.price = 20 @property def name(self): return self.__name @name.deleter def name(self): del self.__name @name.setter def name(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 类方法 ****
类的操作行为 class Goods: __discount = 0.8 def __init__(self,name,price): self.name = name self.__price = price @property def price(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将这个函数变成一个静态方法
class Login: def __init__(self,name,password): self.name = name self.pwd = password def login(self):pass @staticmethod def get_usr_pwd(): # 静态方法 usr = input('用户名 :') pwd = input('密码 :') Login(usr,pwd) Login.get_usr_pwd()
类方法和静态方法 都是类调用的。
对象可以调用类方法和静态方法,一般情况下 推荐用类名调用。
类方法 有一个默认参数 cls 代表这个类 cls
静态方法 没有默认的参数 就象函数一样