文章目录

  • 类与对象
  • 定义简单类
  • 创建只包含对象的方法
  • 创建对象
  • 方法中的self参数
  • 初始化方法
  • 在初始化方法内部定义属性
  • 改造初始化方法 —— 初始化的同时设置初始值
  • 内置方法和属性
  • `__del__` 方法
  • `__str__` 方法
  • 封装
  • 案例一
  • 案例二
  • 案例三
  • 身份运算符
  • 私有属性和私有方法
  • 应用场景及定义方式
  • 伪私有属性和私有方法(科普)
  • 继承
  • 单继承
  • 继承的概念、语法和特点
  • 方法的重写
  • 覆盖父类的方法
  • 对父类方法进行 扩展
  • 关于 `super`
  • 父类的私有属性和私有方法
  • 多继承
  • 多继承的使用注意事项
  • 多态
  • 案例
  • 类与对象

    类(Class): 用来描述具有相同的属性和方法的对象的集合。它定义了该集合中每个对象所共有的属性和方法,对象是类的实例。
    
    类的三要素:类名、属性、方法
    
    类名:大驼峰命名法每个单词首字母大写,无下划线
    
    属性和方法的确定:
    对对象的特征描述通常可以定义成属性
    对象具有的行为通常可以定义成方法
    
    面向对象三大特性:
    
    封装:根据职责将属性和方法封装到一个抽象的 类 中
    继承:实现代码的重用,相同的代码不需要重复的编写
    多态:不同的对象调用相同的方法,产生不同的执行结果,增加代码的灵活度
    

    定义简单类

    创建只包含对象的方法

    class 类名:
        def 方法1(self,参数列表):
            pass
        def 方法2(self,参数列表):
            pass
    #类名大驼峰
    #方法与函数定义方法一致,只是第一个参数为self
    

    创建对象

    对象变量=类名()
    
    `dir` 内置函数返回对象的方法
    

    方法中的self参数

    在python中给对象设置属性,非常的容易,但是不推荐使用
    (不修改类,直接给类增加一个属性)
    对象名.属性=属性值
    #只会给当前对象增加属性值
    class Animal:
    
        def eat(self):
            print("吃饭")
    
        def run(self):
            print("跑步")
    xx = Animal()
    xx.name = "Tom"
    ss = Animal()
    print(xx.name)#返回Tom
    print(ss.name)#报错
    
    哪一个对象调用的方法,self就是哪一个对象的引用(在内存中的地址相同)
    在类封装的方法内部,self 就表示当前调用方法的对象自己
    
    调用方法时,程序员不需要传递 self 参数
    在方法内部
    	可以通过 self. 访问对象的属性
    	也可以通过 self. 调用其他的对象方法
    

    初始化方法

    当使用 类名() 创建对象时,会自动执行以下操作:
    1.为对象在内存中 分配空间 —— 创建对象
    2.为对象的属性 设置初始值 —— 初始化方法(init)
    这个初始化方法 就是 __init__ 方法,__init__ 是对象的内置方法
    __init__ 方法是专用来定义一个类 具有哪些属性的方法!
    
    如:
    class Cat:
        def __init__(self):
            print("这是一个初始化方法")
    tom = Cat()
    >>>这是一个初始化方法
    
    创建对象时会自动调用__init__方法
    

    在初始化方法内部定义属性

    在 __init__ 方法内部使用 self.属性名 = 属性的初始值 就可以 定义属性
    定义属性之后,再使用 Cat 类创建的对象,都会拥有该属性
    
    如:
    class Cat:
        def __init__(self):
            self.name="Tom"
    tom = Cat()
    print(tom.name)
    >>>Tom
    

    改造初始化方法 —— 初始化的同时设置初始值

    在开发中,如果希望在 创建对象的同时,就设置对象的属性,可以对 __init__ 方法进行 改造
    1.把希望设置的属性值,定义成 __init__ 方法的参数
    2.在方法内部使用 self.属性 = 形参 接收外部传递的参数
    3.在创建对象时,使用 类名(属性1, 属性2...) 调用
    如:
    class Cat:
        def __init__(self,new_name):
            self.name = new_name
    
        def eat(self):
            print("%s爱吃鱼" % self.name)
    
    tom = Cat("Tom")
    lazy_cat=Cat("lazy_cat")
    tom.eat()
    lazy_cat.eat()
    
    
    

    内置方法和属性

    __del__ 方法:对象被从内存中销毁前,会被自动调用
    __str__ 方法:返回对象的描述信息,print 函数输出使用
    

    __del__ 方法

    在 Python 中
    当使用 类名() 创建对象时,为对象 分配完空间后,自动调用 __init__ 方法
    当一个对象被从内存中销毁前,会自动调用 __del__ 方法
    
    应用场景:
    __init__ 改造初始化方法,可以让创建对象更加灵活
    __del__ 如果希望在对象被销毁前,再做一些事情,可以考虑一下 __del__ 方法
    
    生命周期:
    一个对象从调用 类名() 创建,生命周期开始
    一个对象的 __del__ 方法一旦被调用,生命周期结束
    在对象的生命周期内,可以访问对象属性,或者让对象调用方法
    
    如:
    class Cat:
        def __init__(self,new_name):
            self.name=new_name
            print("%s来了"%self.name)
        def __del__(self):
            print("%s我去了"%self.name)
    
    tom=Cat("tom")
    print(tom.name)
    
    print("-"*50)
    >>>
    tom来了
    tom
    --------------------------------------------------
    tom我去了
    #在分割线下方输出tom我去了,tom为全局变量,全部执行完成之后才能将tom回收
    
    #可使用del tom对象 这样能提前回收tom
    

    __str__ 方法

    在 Python 中,使用 print 输出对象变量,默认情况下,会输出这个变量引用的对象是由哪一个类创建的对象,以及在内存中的地址(十六进制表示)
    
    如果在开发中,希望使用print输出对象变量时,能够打印自定义的内容(不输出类和地址等信息),就可以利用 __str__ 这个内置方法了
    注意:__str__ 方法必须返回一个字符串
    如:
    class Cat:
        def __init__(self,new_name):
            self.name=new_name
            print("%s来了"%self.name)
    
        def __del__(self):
            print("%s我去了"%self.name)
    
        def __str__(self):
            return "我是小猫[%s]"%self.name
    
    
    tom=Cat("tom")
    print(tom)
    >>>
    tom来了
    我是小猫[tom]
    tom我去了
    
    

    封装

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

    案例一

    1.封装是面向对象编程的一大特点
    2.面向对象编程的第一步 —— 将 属性和方法 封装到一个抽象的类中
    3.外界使用类创建对象然后让对象调用方法
    4.对象方法的细节都被封装在类的内部
    

    如:
    class Person:
        def __init__(self,name,weight):
            self.name=name
            self.weight=weight
    
        def __str__(self):
            return "我的名字叫 %s 体重是 %.2f 公斤"%(self.name,self.weight)
    
        def run(self):
            print("%s爱跑步,跑步锻炼身体"%self.name)
            self.weight-=0.5
    
        def eat(self):
            print("%s是吃货,吃完再减肥"%self.name)
            self.weight+=0.6
    
    x=Person("xiao ming",65.3)
    x.run()
    x.eat()
    print(x)
    
    >>>
    xiao ming爱跑步,跑步锻炼身体
    xiao ming是吃货,吃完再减肥
    我的名字叫 xiao ming 体重是 65.40 公斤`
    

    案例二


    image-20221014101454124

    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):
            return "户型:%s\n总面积:%.2f[剩余:%.2f]\n家具:%s"%(self.house_type,self.area,self.free_area,self.item_list)
    
        def add_item(self,item):
            print("要添加%s"%item)
            #判断家具的面积
            #将家具添加到列表(判断剩余面积是否满足条件)
            #计算剩余面积
            if item.area>self.free_area:
                print("%s面积太大,无法添加"%item.name)
                return
            self.item_list.append(item.name)
            self.free_area-=item.area
    
    #创建家具对象
    bed=HouseItem("席梦思",4)
    chest=HouseItem("衣柜",2)
    table=HouseItem("餐桌",1.5)
    print(bed,chest,table,sep="\n")
    
    #创建房子对象
    my_house=House("两室一厅",60)
    #添加家具
    my_house.add_item(bed)
    my_house.add_item(chest)
    my_house.add_item(table)
    print(my_house)
    

    案例三

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

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4EINvSC0-1665753279837)(C:\Users\98306\AppData\Roaming\Typora\typora-user-images\image-20221014102638240.png)]

    class Gun:
        def __init__(self, model):
            self.model = model
            self.bullet_count = 0
    
        def add_bullet(self, count):
            self.bullet_count += count
    
        def shoot(self):
            if self.bullet_count<=0:
                print("[%s]没有子弹了...." % self.model)
                return
            self.bullet_count -= 1
            print("Peng![%s]发射了一枚子弹" % self.model)
    
    
    class Soldier:
        def __init__(self,name):
            self.name=name
            self.gun=None#新兵没有枪
    
        def fire(self):
            if self.gun is None:
                print("士兵[%s]没枪"%self.name)
                return
            print("[%s]冲锋"%self.name)
            self.gun.add_bullet(50)
            self.gun.shoot()
    
    ak47=Gun("ak47")
    xusanduo=Soldier("xusanduo")
    xusanduo.gun=ak47
    xusanduo.fire()
    print(xusanduo.gun)
    >>>
    [xusanduo]冲锋
    Peng![ak47]发射了一枚子弹
    <__main__.Gun object at 0x000001C069E90408>
    

    身份运算符

    身份运算符用于比较两个对象的内存地址是否一致 —— 是否是对同一个对象的引用
    
    在Python中针对None比较时,建议使用is判断
    is:is 是判断两个标识符是不是引用同一个对象x is y,类似 id(x) == id(y)
    is not:is not 是判断两个标识符是不是引用不同对象	x is not y,类似 id(a) != id(b)
    

    私有属性和私有方法

    应用场景及定义方式

    应用场景:
    在实际开发中,对象的某些属性或方法 可能只希望在对象的内部被使用,而不希望在外部被访问到
    	私有属性就是对象不希望公开的属性
    	私有方法就是对象不希望公开的方法
    
    定义方式:
    在定属性或方法时,在属性名或者方法名前增加两个下划线定义的就是 私有属性或方法
    

    伪私有属性和私有方法(科普)

    提示:在日常开发中,不要使用这种方式访问对象的 私有属性 或 私有方法

    Python 中,并没有 真正意义私有

  • 在给 属性、方法 命名时,实际是对 名称 做了一些特殊处理,使得外界无法访问到
  • 处理方式:在 名称 前面加上 _类名 => _类名__名称
  • python中没有真正意义上的私有,可以通过 对象._类名.__名称来访问私有方法和私有属性

    继承

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

    单继承

    子类拥有 父类 的所有 方法和 属性

    继承的概念、语法和特点

    继承的语法

    class 类名(父类名):
    
        pass
    
    子类继承自父类,可以直接享受父类中已经封装好的方法,不需要再次开发
    
    子类中应该根据职责,封装子类特有的属性和方法
    
    Dog类是Animal类的子类,Animal类是Dog类的父类,Dog类从Animal类继承
    
    Dog类是Animal类的派生类,Animal类是Dog类的基类,Dog类从Animal类派生
    
    继承的传递性:
    C类从B类继承,B类又从A类继承
    那么C类就具有B类和A类的所有属性和方法
    子类拥有父类以及父类的父类中封装的所有属性和法
    
    class Animal:
        def eat(self):
            print("吃")
    
        def drink(self):
            print("喝")
    
        def run(self):
            print("跑")
    
        def sleep(self):
            print("睡")
    
    
    class Dog(Animal):  # Dog类继承Animal类,子类只需要封装自己独有的属性和方法即可
        def bark(self):
            print("汪汪叫")
    
    
    class xiaotianquan(Dog):  # 继承的传递性
        pass
    
    
    # 子类拥有父类所有的属性和方法
    wangcai = xiaotianquan()
    wangcai.eat()
    wangcai.drink()
    wangcai.run()
    wangcai.sleep()
    wangcai.bark()
    
    

    方法的重写

    子类拥有父类的所有方法和属性
    
    子类继承自父类,可以直接享受父类中已经封装好的方法,不需要再次开发
    

    当 父类 的方法实现不能满足子类需求时,可以对方法进行 重写(override)

    重写父类方法有两种情况:

    1. 覆盖父类的方法
    2. 对父类方法进行 扩展
    

    覆盖父类的方法

    如果在开发中,父类的方法实现和子类的方法实现,完全不同
    就可以使用覆盖的方式,在子类中重新编写父类的方法实现
    
    具体的实现方式,就相当于在 子类中定义了一个和父类同名的方法并且实现
    
    重写之后,在运行时,只会调用子类中重写的方法,而不再会调用父类封装的方法
    

    对父类方法进行 扩展

    如果在开发中,子类的方法实现中包含父类的方法实现
    父类原本封装的方法实现是子类方法的一部分
    就可以使用扩展的方式
    1.在子类中重写父类的方法
    2.在需要的位置使用  super().父类方法  来调用父类方法的执行
    3.代码其他的位置针对子类的需求,编写子类特有的代码实现
    

    关于 super

    在 Python中 super 是一个 特殊的类
    super() 就是使用 super 类创建出来的对象
    最常 使用的场景就是在 重写父类方法时,调用 在父类中封装的方法实现
    
    调用父类方法的另外一种方式(知道)
    在 Python 2.x 时,如果需要调用父类的方法,还可以使用以下方式:
    
    父类名.方法(self)
    
    这种方式,目前在 Python 3.x 还支持这种方式
    这种方法 不推荐使用,因为一旦 父类发生变化,方法调用位置的 类名 同样需要修改
    
    提示
    在开发时,父类名 和 super() 两种方式不要混用
    如果使用 当前子类名 调用方法,会形成递归调用,出现死循环
    

    父类的私有属性和私有方法

    1.子类对象不能在自己的方法内部,直接访问父类的 私有属性或私有方法
    2.子类对象可以通过父类的公有方法间接访问到私有属性或私有方法
    	私有属性、方法是对象的隐私,不对外公开,外界以及子类都不能直接访问
    	私有属性、方法 通常用于做一些内部的事情
    

    B的对象不能直接访问 __num2 属性
    B的对象不能在demo方法内访问 __num2 属性
    B的对象可以在demo方法内,调用父类的test方法
    父类的test方法内部,能够访问 __num2 属性和 __test 方法
    

    多继承

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

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

    多继承的使用注意事项

    问题的提出
    
    如果不同的父类中存在同名的方法,子类对象在调用方法时,会调用哪一个父类中的方法呢?
    提示:
    开发时,应该尽量避免这种容易产生混淆的情况! 
    —— 如果父类之间存在 同名的属性或者方法,应该尽量避免使用多继承
    

    多态

    多态 不同的 子类对象调用相同的 父类方法,产生不同的执行结果

    多态可以增加代码的灵活度
    以继承和重写父类方法为前提
    是调用方法的技巧,不会影响到类的内部设计
    

    案例

    需求:
    在Dog类中封装方法game
    	普通狗只是简单的玩耍
    定义XiaoTianDog继承自Dog,并且重写game方法
    	哮天犬需要在天上玩耍
    定义Person类,并且封装一个和狗玩的方法
    	在方法内部,直接让狗对象调用game方法
    

    Person类中只需要让狗对象调用game方法,而不关心具体是什么狗
    game方法是在Dog父类中定义的
    在程序执行时,传入不同的狗对象实参,就会产生不同的执行效果
    

    多态 更容易编写出出通用的代码,做出通用的编程,以适应需求的不断变化!

    class Dog:
        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:
        def __init__(self,name):
            self.name=name
    
        def game_with_dog(self,dog):
            print("%s和%s一起玩"%(self.name,dog.name))
            dog.game()
    
    dahuang=Dog("大黄")
    wangcai=XiaoTianQuan("神*旺财")
    xiaoming=Person("小明")
    xiaoming.game_with_dog(wangcai)
    xiaoming.game_with_dog(dahuang)
    >>>
    小明和神*旺财一起玩
    神*旺财飞到天上去玩耍
    小明和大黄一起玩
    大黄蹦蹦跳跳的玩耍
    #传入不同的对象会产生不同的结果,这个就是多态
    

    !**

    class Dog:
        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:
        def __init__(self,name):
            self.name=name
    
        def game_with_dog(self,dog):
            print("%s和%s一起玩"%(self.name,dog.name))
            dog.game()
    
    dahuang=Dog("大黄")
    wangcai=XiaoTianQuan("神*旺财")
    xiaoming=Person("小明")
    xiaoming.game_with_dog(wangcai)
    xiaoming.game_with_dog(dahuang)
    >>>
    小明和神*旺财一起玩
    神*旺财飞到天上去玩耍
    小明和大黄一起玩
    大黄蹦蹦跳跳的玩耍
    #传入不同的对象会产生不同的结果,这个就是多态
    
    物联沃分享整理
    物联沃-IOTWORD物联网 » Python面向对象编程

    发表评论