python 课堂14 面向对象2 继承 封装 多态

面向对象 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()

猜你喜欢

转载自www.cnblogs.com/qianduoduo123/p/9446252.html