面向对象 2 继承、多态、封装
继承:
python 不管是否显式继承object 都默认继承object。
class SuperClass1:
pass
class SuperClass2:
pass
class Sub1(SuperClass1): # 单继承
pass
class Sub2(SuperClass1,SuperClass2): # 多继承
pass
bases 查看继承
print(SuperClass1.__bases__) # 不指定继承,就默认继承 object
(<class 'object'>,)
print(Sub1.__bases__) # 单继承
(<class '__main__.SuperClass1'>,)
print(Sub2.__bases__) # 多继承
(<class '__main__.SuperClass1'>, <class '__main__.SuperClass2'>)
继承属性查找顺序:
Sub2.mro() ===> sub2.__mro__() 相同。打印继承的类和顺序。
经典类,深度优先,新式类,广度优先。
print(Sub2.mro())
class Foo:
def f1(self):
print('this is Foo func f1:')
def f2(self):
print('this is Foo func f2:')
self.f1()
class Bar(Foo):
def f1(self):
print('this is bar f1:')
b = Bar()
b.f2()
#this is Foo func f2:
#this is bar f1:
1、b 先在自己对象属性 __dict__中查找,没有,
2、就到自己的类 Bar 的dict 中找,没有
3、就Bar 的父类 Foo 中去找。
4、找到后,f2 函数中 self.f1(),self 就是对象本身 b 相当于 b.f1()
5、再找自己的对象属性,没有找自己的类属性,Bar() f1.
继承:调用父类属性。
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):
# 直接使用父类名调用 __init__()方法获取实例属性。
# 调用__init__()方法,将子类的形参传入,获取父类中定义的属性。
# 即便没有继承关系,也可以这样调用。
Vehicle.__init__(self,name,speed,load,power)
# 使用super()函数调用父类 __init__() 方法,获取实例属性。
# 1、动态调用,可以不管父类是什么都可以用。
# 2、省略了参数中的self.
# 3、必须有继承关系,super()才可以使用。
super().__init__(name, speed, load, power)
self.line = line
def run(self):
print('subway run....')
super().run() # 调用父类run()方法
多态:
多态、同一种事物的多种形态
多态性,不考虑实例类型的情况下,直接使用实例
多态,动物,不同形态 人 狗
抽象类: 给子类提供标准,规范接口
import abc
class Animal(metaclass=abc.ABCMeta):
@ abc.abstractmethod
def eat(self):
pass
@ abc.abstractmethod
def run(self):
pass
class People(Animal):
def eat(self):
print('people eating')
def run(self):
print('people is running')
class Dog(Animal):
def eat(self):
print('dog eating')
def run(self):
print('dog is running')
peo = People()
dog = Dog()
不考虑实例类型,使用实例。不管是人是狗,都是动物,就可以使用动物的run()方法。只要是动物,就可以当做动物来用。这就是多态的好处。
peo.run()
dog.run()
定义统一的调用方式,不用去管具体的实例,只要实例属于动物。
def eat(animal):
animal.eat()
def run(animal):
animal.run()
# 不考虑是人是狗,只要是动物,就可以传入,调用吃的方法。还可以扩展,添加猫类,只需要猫也实现eat()方法。
eat(peo)
run(dog)
多态,增加程序灵活性和扩展性,灵活性。
灵活性,不管对象是什么都可以直接使用相同的方法去调用。
扩展性,只要类实现了同样的方法,不许要改变调用方式。
鸭子类型:
看起来像鸭子,走路和叫声像鸭子,就可以当作是鸭子。
即便类之间没有继承关系,只要相似,内部使用相同的方法,就可以实现统一的调用。
例如 list tuple str
l = list([1,2,3])
t = tuple([4,5,6])
s = str('qianlei')
l.__len__()
t.__len__()
s.__len__()
len(l)
len(t)
len(s)
list,tuple,str 内部都实现了__len__()方法,就可以看作一样的内容,同一使用len()方法
封装 :
封装,对类属性进行影藏
class Foo():
__name = 'qianlei' # 被转化为 _Foo__name
def __run(self): # 转化为 _Foo__run
print('Foo,run')
print(Foo.__dict__)
'_Foo__name': 'qianlei',
'_Foo__run': <function Foo.__run at 0x05A2C858>,
Foo.__run() # 直接调用是找不到的,因为内部将名称改变了。
Foo._Foo__run(123) # python 并不真正的不给外部调用影藏属性。、
class Foo():
def __func(self):
print('this Foo func')
def func1(self):
print('this is Foo func1')
self.__func() # 这里的名称被改为 b.Foo_func1 ,所以只会调用这个函数中的func
class Bar(Foo):
def __func(self): # 名称被改为 _Bar__func
print('this is bar func2')
b = Bar()
b.func1()
b.__name = 'qianlei'
print(b.__name)
创建类之后,就无法影藏属性
b.__sex = 'male'
print(b.__sex) # 可以直接打印,无法隐藏
封装的意义:
一、明确区分内外,内部数据不允许外部直接调用,可以提供接口给外部,外部间接调用属性。接口可以添加各种使用条件。
二、隔离复杂度,内部使用影藏数据,将复杂的逻辑组合为一个简单接口,外部不需要管内部的逻辑,只需要简单调用即可。
抽象类、强制继承的类必须实现抽象类中定义的方法。
1、统一类中的方法名,方便使用者调用。
猫,狗,猪都有走的方法,不加以规范会起不同的名称,这样,调用时会使调用者迷糊。
使用抽象类进行规范,可以固定名称,每一个类都必须实现同样名称的走方法,比如run()
这样调用时,不管是什么类,只要想要走的方法,就使用run(),降低调用难度。
import abc
class Animal(metaclass=abc.ABCMeta):
@ abc.abstractmethod
def run(self):
pass
@ abc.abstractmethod
def eat(self):
pass
继承抽象类的类,必须实现抽象类中定义的方法。
class Dog(Animal):
def run(self):
print('dog is running .')
def eat(self):
print('dog is eating ')
class Cat(Animal):
def run(self):
print('cat is runing ')
def eat(self):
print('cat is eating ')
d = Dog()
c = Cat()
组合 :
把其他类的对象设置为类的属性,就可以直接拥有该对象中的属性,就是类的组合,和类的继承要区分开。
组合与继承,都是解决重复代码的问题,减少代码量
组合:是拥有的关系,学生拥有课程。所以拥有课程的属性。
继承:是什么是什么的关系,学生是人。所以拥有人的属性。
class People:
def __init__(self,name,sex,age):
self.name = name
self.sex = sex
self.age = age
def eat(self):
print('%s is eating'%self.name)
class teacher(People):
def __init__(self,name,sex,age,salary):
super().__init__(name,sex,age)
self.salary = salary
def teach(self):
print('%s is teaching .'%self.name)
class Student(People):
def __init__(self,name,sex,age,grade):
super().__init__(name,sex,age)
self.grade = grade
def learn(self):
print('%s is learning.'%self.name)
class Course:
def __init__(self,name,cost):
self.name = name
self.cost = cost
def info(self):
print('this couse name %s need %s money'%(self.name, self.cost))
stu1 = Student('qianlei','male',23,4)
lesson = Course('python',3000)
stu1.eat() # 学生类中有父类属性 继承
stu1.learn() # 学生类中有自己的属性
stu1.lesson = lesson # 学生类中包含课程对象 类的组合。
stu1.lesson.info()