天天看点

Python学习笔记(七)——面向对象的三大特征——封装、继承、多态

在上一个笔记中,学习了类和对象的相关知识。这个章节来说一说面向对象。在学习面向对象的语言中,不得不提面向对象的三大特征——封装、继承、多态。

1. 封装

根据职责将属性和方法封装到一个抽象的类中。

下面将用示例来说明:(类与类直接可以空两行)

示例一:

class HouseItem:
    '''表示家具类'''
    def __init__(self,name,area):
        self.name = name
        self.area = area
    def __str__(self):
        return "[%s]的占地面积是%.2f"%(self.name,self.area)

class House:
    def __init__(self,house_type,area):
        self.house_type = house_type
        self.area = area
        #这两个属性不需要外界传入,可以直接定义。
        #剩余面积
        self.free_area = area
        #家具名称列表
        self.item_list = []
    def __str__(self):
        '''Python能够自动将一对括号内部的代码连接在一起'''
        return ("户型:%s]\n总面积:%.2f]\n添加的家具是:%s\n剩余:%.2f\n"
                %(self.house_type,self.area,
                  self.item_list,self.free_area))
    def add_item(self,item):
        '''添加家具
        1.判断家具的面积是否超过剩余面积,如果超过提示不能添加这件家具
        2.将家具的名称追加到家具名称列表中
        3.用房子的剩余面积-家具面积'''

        if item.area >= self.area:
            print("%s的面积太大,无法添加" %item.name)

        self.item_list.append(item.name)
        self.free_area = self.area - item.area
        print()
#1.创建家具
bed = HouseItem("席梦思",4)
chest = HouseItem("衣柜",2)
table = HouseItem("餐桌",1.5)
print(bed)
# 2.创建房子对象
new_house = House("两室一厅",80)

new_house.add_item(bed)

print(new_house)
           

小结:

主程序只负责创建房子对象和家具对象,
           

示例二:

描述:一个对象的属性可以是另外一个类创建的对象

需求:

士兵许三多有一把98k

士兵可以开火

枪能够发射子弹

枪装填子弹–增加子弹数量

首先提取类(名词):士兵类,枪类

假设每一个新兵都没有枪,定义没有初始值的属性。设置为None

class Gun(object):
    def __init__(self,model,):
        """枪的初始化
        :param model: 枪的型号
        """
        self.model = model
        # 子弹的数量
        self.bullet_count  = 0
    def add_bullet(self,count):
        '''添加子弹'''
        print("可以添加子弹")
        self.bullet_count += count
    def shoot(self):

        # 1.判断子弹数量
        if self.bullet_count <= 0:
            print("[%s]没有子弹了"%self.model)
            return
        # 2.发射子弹
        self.bullet_count -= 1
        # 3.提示发射信息
        print("tutututututu")



class Soldier(object):
    def __init__(self,name):
        # 1.新兵的属性
        self.name = name
        # 2.加入新兵没有枪
        self.gun = None

    def fire(self):
        '''士兵开火
        1.判断是否有枪
        2.喊一声口号
        3.装填子弹
        4.射击'''
        if self.gun is None:
            print("[%s]还没有枪。。。"%self.name)
            return
        print("冲啊")
        self.gun.add_bullet(50)
        self.gun.shoot()
        print("士兵可以开火")

# 创建枪对象
new_gun = Gun("98k")
# new_gun.add_bullet(30)
# new_gun.shoot()
# 创建士兵
xsd = Soldier("许三多")
xsd.gun = new_gun #相当于有了一把枪
xsd.fire()

print(xsd.gun)
           

此处补充一个小知识点:

1. is 与 == 区别:

is 用于判断两个变量引用对象是否为同一个,
 == 用于判断引用变量的值是否相等。
           

2. object 类

在定义类时,如果没有父类,建议统一继承object。
class 类名(object):
	pass
           

2. 继承

实现代码的重用,相同的代码不需要重复的编写。

示例展示:

class Anima(object):
    def eat(self):
        print("吃")
    def drink(self):
        print("喝")
    def run(self):
        print("跑")


class Dog(Animal):
    def bark(self):
        print("汪汪叫")
        
wang = Dog()
wang.eat()
wang.run()
wang.drink()
wang.bark()

结果:
吃
跑
喝
汪汪叫
           

小结:Dog类是Animal类的派生类,Animal类是Dog类的基类

继承具有传递性。

class Animal:
    def eat(self):
        print("吃")
    def drink(self):
        print("喝")
    def run(self):
        print("跑")

class Dog(Animal):
    def bark(self):
        print("汪汪叫")

class XiaoTianQuan(Dog):
    def fly(self):
        print("会飞")
wang = XiaoTianQuan()
wang.eat()
wang.run()
wang.drink()
wang.bark()
wang.fly()


吃
跑
喝
汪汪叫
会飞
           

2.1 重写

在继承中,如果父类方法不能满足子类的需求,在子类中可以重写父类方法。(方法名相同,实现过程不同,且可以覆盖父类方法)

class Animal:
    def eat(self):
        print("吃")
    def drink(self):
        print("喝")
    def run(self):
        print("跑")

class Dog(Animal):
    def bark(self):
        print("汪汪叫")

class XiaoTianQuan(Dog):
    def bark(self):
        print("wangwangwnag-----")
    def fly(self):
        print("会飞")


wang = XiaoTianQuan()
wang.eat()
wang.run()
wang.drink()
wang.bark()
wang.fly()

结果:
吃
跑
喝
wangwangwnag-----
会飞
           

2.2 super()

在重写父类的方法时,希望原本的父类方法调用,在需要的位置使用super().父类方法,来调用父类方法的执行。

代码演示:

class Animal:
    def eat(self):
        print("吃")
    def drink(self):
        print("喝")
    def run(self):
        print("跑")

class Dog(Animal):
    def bark(self):
        print("汪汪叫")

class XiaoTianQuan(Dog):
    def bark(self):
        # 1.使用super().调用原本在父类中封装的方法
        print("神犬的叫声")
        super().bark()
    def fly(self):
        print("会飞")


wang = XiaoTianQuan()
wang.bark()
wang.fly()

神犬的叫声
汪汪叫
会飞
           

2.3 多继承

子类可以拥有多个父类,并且具有所有父类的属性和方法。

格式:

class 子类名(父类名1,父类名2):
	pass
           

在多继承中,应避免父类1和父类2中存在相同的方法。

代码演示:

class A:
    def demo1(self):
        print("AAAA---demo1")
    def demo2(self):
        print("AAAA---demo2")


class B():
    def demo2(self):
        print("BBB---demo2")
    def demo3(self):
        print("BBB----demo3")
class C(B,A):
    pass

#当创建对象时,调用demo2(),则先调用B类中的方法。调用的时候哪个在前面就先调用哪个
c = C()
c.demo2()
# 可以使用__mro__,输出调用的顺序。
print(C.__mro__)

结果如下:
BBB---demo2
(<class '__main__.C'>, <class '__main__.B'>, <class '__main__.A'>, <class 'object'>)
           

注意:

Python中MRO(Method resolution order)----方法搜索顺序。从左到右的顺序查找
print(C.__mro__)
           

小结:

多继承可以让子类对象,同时具有多个父类的属性和方法

2.4 私有属性和私有方法

对于父类的私有属性和私有方法的调用,我们将在下节笔记中详细讲述。

多态

不同的对象调用相同的方法,产生不同的执行结果,以继承和重写父类方法为前提,可以增加代码的灵活度。

代码演示:

class Dog(object):
    def __init__(self,name):
        self.name = name
    def game(self):
        print("%s在玩耍"%self.name)

class XiaoTianQuan(Dog):
    def game(self):
        print("%s会上天"%self.name)


class Person(object):
    def __init__(self,name):
        self.name = name
    def game_with_dog(self,dog):
        print("%s 和 %s玩耍"%(self.name,dog.name))
        dog.game()

# 1.创建一个狗对象
#wangcai = Dog("旺财")
wangcai = XiaoTianQuan("会飞的旺财")

# 2.创建一个小明对象
xiaoming = Person("小明")
xiaoming.game_with_dog(wangcai)
           

哈哈!您已成功了一大半。