**类知识点2**
**在子类中调用父类的两种方法**
方式一 父类名.父类方法()
class Vehicle: # 定义交通工具类
Country = 'China'
def __init__(self, name, speed, load, power):
self.name = name
self.speed = speed
self.load = load
self.power = power
def run(self):
print('开动啦...')
class Subway(Vehicle): # 地铁类嵌入交通工具类
def __init__(self, name, speed, load, power, line):
Vehicle.__init__(self, name, speed, load, power) # 父类名.父类方法
self.line = line
def run(self):
print('地铁%s号线欢迎您' % self.line)
Vehicle.run(self)
line13 = Subway('中国地铁', '180m/s', '1000人/箱', '电', 13) # 实例化类,创造出一个类
line13.run() # 类绑定方法
方法1中,使用了父类名.父类方法(),
Vehicle.__init__(self, name, speed, load, power)
方法二 使用super()函数
class Vehicle: #定义交通工具类
Country='China'
def __init__(self,name,speed,load,power):
self.name=name
self.speed=speed
self.load=load
self.power=power
def run(self):
print('开动啦...')
class Subway(Vehicle): # 地铁
def __init__(self,name,speed,load,power,line):
#super(Subway,self) 就相当于实例本身 在python3中super()等同于super(Subway,self)
super().__init__(name,speed,load,power)
self.line=line
def run(self):
print('地铁%s号线欢迎您' %self.line)
super(Subway,self).run()
class Mobike(Vehicle):#摩拜单车
pass
line13=Subway('中国地铁','180m/s','1000人/箱','电',13)
line13.run()
方法2使用了super(),
super().__init__(name,speed,load,power)
super()相当于实例本身,在python3中super()等同于super(Subway,self) 方式一不依赖于继承,方式二依赖继承,即便没有直接的继承关系,super仍然会按照mro继续往后找
class A:
def test(self)
super().test()
class B:
def test(self):
print('from B')
class C(A,B):
pass
c=C()
c.test() #打印结果:from B
在以上代码中,c=C(),表示实例化C类,创建c对象,c.test(),绑定test()方法属性到c对象,由于c无test方法属性,类C也没有,因此将从继承的A类里找,找到test(),因为test()方法属性里出现super().test(),super()的意义在于即使没有继承关系,仍然会按照mro线性顺序列表继续往后找对象基类。
**组合与重用性**
软件重用的重要方式除了继承之外还有另外一种方式,即:组合
组合指的是,在一个类中以另外一个类的对象作为数据属性,称为类的组合
继承中,类与类之间的关系为什么是什么的关系,组合则是什么有什么的关系
class Head: # 英雄头饰类
def head(self):
print('猪头')
class Equip: #武器装备类
def fire(self):
print('release Fire skill')
class Riven: #英雄Riven的类,一个英雄需要有装备,还可以装扮头像,因而需要组合Equip,Head类
camp='Noxus'
def __init__(self,nickname):
self.nickname=nickname
self.equip=Equip()
self.head=[] #用Equip类产生一个装备,赋值给实例的equip属性
r1=Riven('锐雯雯')
r1.equip.fire() # 可以使用组合的类产生的对象所持有的方法
r1.head.apend(Head())
r1.head[0].head()# 可以使用组合的类产生的对象所持有的方法
release Fire skill
猪头
** 接口**
接口:提供了一个类的集合,可以把接口当作类函数的集合,让子函数去实现功能
归一化:基于同一个接口实现的类
**抽象类**
类是从一堆对象中抽取相同的内容,抽象类就是从一堆类中抽取相同的内容而来的,内容包括数据属性和函数属性,该类不能被实例化,只能被继承,且子类必须实现抽象方法。这一点与接口有点类似,但其实是不同的。
** 在python中实现抽象类**
#一切皆文件
import abc #利用abc模块实现抽象类
class All_file(metaclass=abc.ABCMeta):
all_type='file'
@abc.abstractmethod #定义抽象方法,无需实现功能
def read(self):
'子类必须定义读功能'
pass
class Txt(All_file):
pass
t1=Txt() # 程序报错
会报错是因为其在继承All_file类之后没有定义read的抽象方法,实现read功能,改正如下
class Txt(All_file): #子类继承抽象类,但是必须定义read方法
def read(self):
print('文本数据的读取方法')
wenbenwenjian=Txt()
wenbenwenjian.read()
print(wenbenwenjian.all_type)
**抽象类与接口**
抽象类的本质还是类,指的是一组类的相似性,包括数据属性(如all_type)和函数属性(如read、write),而接口只强调函数属性的相似性。
抽象类是一个介于类和接口直接的一个概念,同时具备类和接口的部分特性,可以用来实现归一化设计
**多态**
多态指的是一类事物有多种形态, 动物有多种形态:人,狗,猪
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')
**多态性**
指在不考虑实例类型的情况下使用实例,多态性分为静态多态性和动态多态性
多态性好处
1 增加了程序的灵活性
2 增加了程序额可扩展性
静态多态性:如任何类型都可以用运算符+进行运算
动态多态性:如下
peo=People()
dog=Dog()
pig=Pig()
#peo、dog、pig都是动物,只要是动物肯定有talk方法
#于是我们可以不用考虑它们三者的具体是什么类型,而直接使用
peo.talk()
dog.talk()
pig.talk()
#更进一步,我们可以定义一个统一的接口来使用
def func(obj):
obj.talk()
**鸭子类型 **
Python崇尚鸭子类型,即‘如果看起来像、叫声像而且走起路来像鸭子,那么它就是鸭子’
python程序员通常根据这种行为来编写程序。
例如,如果想编写现有对象的自定义版本,可以继承该对象
也可以创建一个外观和行为像,但与它无任何关系的全新对象,后者通常用于保存程序组件的松耦合度。
class TxtFile:
def read(self):
pass
def write(self):
pass
class DiskFile:
def read(self):
pass
def write(self):
pass
**封装**
隐藏
在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是可以访问到的,即这种操作并不是严格意义上的限制外部访问,仅仅只是一种语法意义上的变形
自动变形的特点:
类中定义的__x只能在内部使用,如self.__x,引用的就是变形的结果。
这种变形其实正是针对外部的变形,在外部是无法通过__x这个名字访问到的。
在子类定义的__x不会覆盖在父类定义的__x,因为子类中变形成了:_子类名__x,而父类中变形成了:_父类名__x,即双下滑线开头的属性在继承给子类时,子类是无法覆盖的。
#把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
self.__fa()变成_A__fa,fa只在A类内部使用,如果是self.fa(),则返回到对象b里使用。