一.继承性
含义:继承是一种创建新类的方式,在python中,新建的类可以继承一个或多个父类,父类又可称为基类或超类,新建的类称为派生类或子类
类的继承分为 单继承 和 多继承
#单继承 #class ParentClass1: #定义父类 # pass #class ParentClass2: #定义父类 # pass #class SubClass1(ParentClass1): #单继承,基类是ParentClass1,派生类是SubClass # pass #class SubClass2(ParentClass1,ParentClass2): #python支持多继承,用逗号分隔开多个继承的类 # pass
查看继承
>>> SubClass1.__bases__ #__base__只查看从左到右继承的第一个子类,__bases__则是查看所有继承的父类 (<class '__main__.ParentClass1'>,) >>> SubClass2.__bases__ (<class '__main__.ParentClass1'>, <class '__main__.ParentClass2'>)
疑问:如果没有指定基类,python的类会默认继承object类,object是所有python类的基类,它提供了一些常见方法(如__str__)的实现。
抽象:即抽出类似或者比较像的部分
继承实例:
# class Animal: # ''' # 人和狗都是动物,所以创造一个Animal基类 # ''' # def __init__(self, name, aggressivity, life_value): # self.name = name # 人和狗都有自己的昵称; # self.aggressivity = aggressivity # 人和狗都有自己的攻击力; # self.life_value = life_value # 人和狗都有自己的生命值; # def eat(self): # print('%s is eating'%self.name) # class Dog(Animal): # pass # class Person(Animal): # pass # egg = Person('egon',10,1000) # ha2 = Dog('二愣子',50,1000) # egg.eat() # ha2.eat()
派生
含义:子类在父类方法和属性的基础上产生了新的方法和属性
注意:当然子类也可以添加自己新的属性或者在自己这里重新定义这些属性(不会影响到父类),需要注意的是,一旦重新定义了自己的属性且与父类重名,那么调用新增的属性时,就以自己为准了。
在python3中,子类执行父类的方法也可以直接用super方法.
class A: def hahaha(self): print('A') class B(A): def hahaha(self): super().hahaha() #super(B,self).hahaha() #A.hahaha(self) print('B') a = A() b = B() b.hahaha() super(B,b).hahaha()
抽象类与接口类
继承有两种用途:
一:继承基类的方法,并且做出自己的改变或者扩展(代码重用)
二:声明某个子类兼容于某基类,定义一个接口类Interface,接口类中定义了一些接口名(就是函数名)且并未实现接口的功能,子类继承接口类,并且实现接口中的功能
from abc import ABCMeta,abstractmethod
class Payment(metaclass=ABCMeta):
'''
接口类:
这个类不可以被实例化,规范所有支付功能必须实现pay方法
'''
@abstractmethod
def pay(self,money):
pass
class Alipay: ''' 支付宝支付 ''' def pay(self,money): print('支付宝支付了%s元'%money) class Applepay: ''' apple pay支付 ''' def pay(self,money): print('apple pay支付了%s元'%money) def pay(Payment,money): ''' 支付函数,总体负责支付 对应支付的对象和要支付的金额 ''' Payment.pay(money) p = Alipay() pay(p,200)
抽象类是介于类和接口之间的概念,同时具备类和接口的部分特性,可以用来实现归一化设计。
1.多继承问题
在继承抽象类的过程中,我们应该尽量避免多继承;
在继承接口的时候,鼓励多继承接口
接口隔离原则: 使用多个专门的接口,而不使用单一的总接口。即客户端不应该依赖那些不需要的接口。
2.方法的实现
在抽象类中,我们可以对一些抽象方法做出基础实现;
而在接口类中,任何方法都只是一种规范,具体的功能需要子类实现
3.继承顺序
关于新式类和经典类:从字面上区分:如果当前的类继承了父类或者object类,就是新式类,否则就是经典类
当类是经典类,多继承情况下,会按照深度优先的方式查找
当类是新式类,多继承情况下,会按照广度优先的方式查找
class A(object): def test(self): print('from A') class B(A): def test(self): print('from B') class C(A): def test(self): print('from C') class D(B): def test(self): print('from D') class E(C): def test(self): print('from E') class F(D,E): # def test(self): # print('from F') pass f1=F() f1.test() print(F.__mro__) #只有新式才有这个属性可以查看线性列表,经典类没有这个属性 #新式类继承顺序:F->D->B->E->C->A #经典类继承顺序:F->D->B->A->E->C #python3中统一都是新式类 #pyhon2中才分新式类与经典类 继承顺序
二.多态性
三.封装性
定义:说白了就是把一个类的属性和它的方法收纳到一个包里,比如汽车类,它有price和type等连个属性,另外它还有跑的技能或者行为,这样一个类就体现了面向对象的封装性。
好处:将变化隔离;便于使用;提高复用性;提高安全性
封装原则:将不需要对外提供的内容都隐藏起来;把属性隐藏,提供公共方法对其访问。
1.私有变量
在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的形式访问到. #A._A__N是可以访问到的,即这种操作并不是严格意义上的限制外部访问,仅仅只是一种语法意义上的变形
变形的特点:
1.类中定义的__x只能在类内部使用,如self__x 引用的就是变形结果
2.在外部无法通过这种形式访问
3.在子类定义的__x不会覆盖在父类定义的__x,因为子类中变形成了:_子类名__x,而父类中变形成了:_父类名__x,即双下滑线开头的属性在继承给子类时,子类是无法覆盖的。
当然,在外部我们可以通过a._类名__属性进行访问
2.私有方法
在继承中,如果不想让子类覆盖父类的方法,可以将父类的方法定义为私有
举例:
#把fa定义成私有的,即__fa class A: def __fa(self): #在定义时就变形为_A__fa print('from A') def test(self): self.__fa() #只会与自己所在的类为准,即调用_A__fa class B(A): def __fa(self): print('from B') b=B() b.test() from A
3.property特性
含义:是一种特殊的属性,访问它时会执行一段功能(函数)然后返回值
举例:
import math class 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.1592653589793 62.83185307179586 ''' #圆的周长和面积
注意:此时area,period不能被赋值
使用原因:遵循了统一的访问原则,说白了就是大家都这么调如果你用其他方式调用虽然结果可以实现,但不利于公共使用。
一个静态属性property本质就是实现了get,set,deleter方法
class Foo: @property def AAA(self): print('get的时候运行我啊') @AAA.setter def AAA(self,value): print('set的时候运行我啊') @AAA.deleter def AAA(self): print('delete的时候运行我啊') #只有在属性AAA定义property后才能定义AAA.setter,AAA.deleter f1=Foo() f1.AAA f1.AAA='aaa' del f1.AAA class Foo: def get_AAA(self): print('get的时候运行我啊') def set_AAA(self,value): print('set的时候运行我啊') def delete_AAA(self): print('delete的时候运行我啊') AAA=property(get_AAA,set_AAA,delete_AAA) #内置property三个参数与get,set,delete一一对应 f1=Foo() f1.AAA f1.AAA='aaa' del f1.AAA
使用案例:
class Goods: def __init__(self): # 原价 self.original_price = 100 # 折扣 self.discount = 0.8 @property def price(self): # 实际价格 = 原价 * 折扣 new_price = self.original_price * self.discount return new_price @price.setter def price(self, value): self.original_price = value @price.deleter def price(self): del self.original_price obj = Goods() obj.price # 获取商品价格 obj.price = 200 # 修改商品原价 print(obj.price) del obj.price # 删除商品原价