python基础06面向对象

面向对象和面向过程 这个是非常重要的编程思想

面向过程和面向对象

面向过程和面向对象是2种不同的编程风格

  • 面向过程:主要考虑功能的实现步骤和过程,就是怎么去实现,多使用函数相互结合调用实现,就是一步一步的完成,必须完成上面的步骤,才能进行下一步

  • 面向对象:主要考虑动作的主体和相互关系,就是谁去实现,怎么配合,使用类的继承或组合实现,只要找到对象,就可以让对象帮我们完成操作(不需要管对象如何实现的)

面向过程的实现逻辑:

  • 拆分过程

  • 在定义函数实现每个过程(过程可以包含子过程及相互调用)

  • 在主函数中㐉调用各个过程函数,完成整个流程

python 复制代码
# 函数定义
def 打开冰箱门():
    pass

def 把大象塞入冰箱():
    pass

def 关闭冰箱门():
    pass

# 函数调用
打开冰箱门()
把大象塞入冰箱()
关闭冰箱门()

面向对象将不同的操作主体进行分组,然后指挥不同的对象组合完成不同的操作

面向对象实现的逻辑:

  • 根据动作主体进行建模,即需要几种对象(角色),每个对象需要哪些属性和方法

  • 设计各个对象需要的类

  • 在主流程中将每个类生成对象,组合对象完成整个流程操作

python 复制代码
# 按对象定义类
class 冰箱:
    def 开门(self):
        pass
    def 关门(self):
        pass

class 大象:
    def 进冰箱(self):
        pass

# 调用类生成具体对象
b = 冰箱()
e = 大象()
b.开门()
e.进冰箱()
b.关门()

生活中面向对象的事情:外卖(外卖骑手),汽车,人,手机,杯子

bash 复制代码
最经典:汽车
类(模板):汽车
对象(具体实物):你的奔驰、我的比亚迪、路边出租车
属性(特征):颜色、品牌、车速、座位数
方法(动作):开车、刹车、鸣笛、加油


手机
类:手机
对象:苹果手机、华为手机
属性:尺寸、电量、颜色
方法:打电话、刷视频、拍照

动物
类:小狗
对象:金毛、泰迪、土狗
属性:毛色、体重
方法:汪汪叫、摇尾巴、跑

类和对象

类是图纸,对象是按照这个图纸造出来的实物

属性:东西长什么样子

方法:东西能干啥

类是一个抽象的概念,对象是一个具体的概念

对象是一个具体的概念

在面向对象编程世界中,一切皆为对象,对象都有属性和行为,每个对象都是独一无二的(隔离的),而且对象一定属于某个类

对象的属性是对象的静态特征,对象的行为是对象的动态特征

类和对象的创建

创建了类后,需要创建一个对象,对象是类的具体化

每一个对象都是唯一的,都是一个地址,有了对象后,使用对象.方法,就能调用类中的方法了

创建了一个对象后,还能再次创建多个对象,可以创建无数的对象,对象之间是相互独立的

python 复制代码
# 创建一个类,类的首字母需要大写,规范
class Car():
    color = "red"  # 类属性
    price = "20w"
    km = "100km"

    def automanage(self):  # 方法
        print("智能管理")
    def autodrive(self):
        print("智能导航")


# 创建对象
wenjie = Car()
print(wenjie)  # 存储的是对象的地址

print(wenjie.color)  # 访问类属性

wenjie.price = "30w"  # 修改类属性
print(wenjie.price)

wenjie.size = "4m"  # 添加对象属性,只属于这个对象的,其他对象不能使用
print(wenjie.size)

wenjie.autodrive()  # 调用方法


# 再次创建一个对象出来
xiaomi = Car()
print(xiaomi.km)

xiaomi.autodrive()


# 每个对象都是独立的

类和对象的实例关系

self参数

self作用:

  • 可以在方法里面相互使用属性,self可以访问类的属性

  • self指的的是当前对象的本身,就是当前对象的地址

python 复制代码
# 创建一个类
class Human():
    h = "1.7"
    w = "70kg"

    def eat(self):
        print(self)  # 打印self,里面存储的是传入的对象的地址,默认传入一个对象地址给self
        print("吃饭")
        self.h = "1.8"  # self.属性 修改类属性  self就是对象,因此可以使用对象来使用属性

r = Human()  # 创建了一个对象
print(r)  # 打印对象地址,跟self一样的地址
r.eat()   # 对象调用方法,执行了修改类属性的操作
print(r.h) # 对象输出修改后的属性

# 此时再次创建一个对象
q = Human()
print(q.h)  # 打印属性,是原来的类属性,因为没有调用方法,上面修改的是对于r这个对象的,对象之间是隔离的,互不干扰的

就是实际的对象还没有创建出来的时候,使用self.属性可以实现修改,然后当创建对象的时候,直接就传入self,实现了修改,就是方便了操作

self可以访问类的属性

类中的属性和方法

举一个案例:车(类)

bash 复制代码
class 车:
   #  特征:属性,本质就是变量,变量名=值
   
    颜色 = "黑"
    长度 = "4.5m"

    # 方法:本质就是函数,写在类里面的函数,我们叫为方法 
    def 启动(self):
        print("启动功能")
    
    def 自动驾驶(self):
        print("自动驾驶功能")

对象初始化方法(魔术方法)

也有很多的称呼

这个构造方法,在创建的时候,就会被自动的调用,不需要手动调用

就是创建的属性需要不一样的话,就可以使用构造方法,就需要变化的属性

相同的属性就放在类属性中,就是不变的,创建多个对象,使用这个属性的值不变的情况

python 复制代码
# 就是上面的类中属性是写死的,
class Person():
    h = "1.8"  # 创建对象的时候,这个是h是写死的
    def __init__(self,w):
        self.w = w # 这个就是活的,没有被写死,传参进来

# 这个构造方法就能传参进去,实现了不同

使用了构造方法的话,创建对象就需要传参进去,这个方法是自动调用的


class Person():
    def __init__(self,name):
        self.name = name   # 实例属性
        print(self.name)
    def eat(self,food):
        self.food = food  # food是一个局部变量,self.food是一个实例变量,这样其他方法也可以访问这个变量
        print(self.name + "正在吃" + self.food)

# 创建对象的时候,需要传参进去
tom = Person("tom")
tom.eat("apple")

字符串构造方法,必须返回一个字符串,也就是return返回字符串

python 复制代码
class Dog():
    def __init__(self,name):
        self.name = name
    def __str__(self):  # str构造方法只有一个self参数,不能添加其他的参数
        return f"狗的名字叫{self.name}"
d = Dog("jerry")
print(d)  # 打印的就是return返回的语句

类属性和实例属性

类属性:就是在类中创建的属性,属于公共的

对象属性(实例属性):通过对象创建的属性,只属于这个对象

对象名存储的是当前对象的地址

python 复制代码
class Student():
    role = "学生"  # 类属性

    def __init__(self,name,age):
        self.name = name  # 实例属性,通过对象来创建的属性
        self.age = age

tom = Student("tom",18)  # 创建对象
print(tom.role)  # 使用对象来引用类属性
print(tom.name,tom.age)  # 使用对象来引用对象属性

print(Student.role)  # 使用类名来引用类属性

类方法,实例方法,静态方法

实例方法:就是普通的方法,self代表实例本身,能够调用属性

类方法:cls代表当前类名,能调用类属性,不能调用实例属性

静态方法:无self,cls,只是普通的函数,放在类里面而已

python 复制代码
class Student():
    role = "学生"

    def __init__(self,name,age):
        self.name = name
        self.age = age

    def get_name(self):
        return self.name

    @classmethod
    def get_class_role(cls):
        return cls.role

    @staticmethod
    def get_command():
        return "我是静态方法"

tom = Student("tom",18)

# 使用对象调用
print(tom.get_name())  # 对象调用实例方法
print(tom.get_class_role())  # 对象调用类方法
print(tom.get_command())  # 对象调用静态方法

# 使用类名来调用

print(Student.get_class_role()) # 类名调用类方法
print(Student.get_command())  # 类名调用静态方法

# 类名调用实例方法,需要传入一个对象才能,因为这个self需要接收一个对象
print(Student.get_name(tom))

面向对象的三个特性

封装(打包)

封装:把属性和方法打包放进类里,隐藏内部细节,对外只留使用入口

作用:代码整洁、安全、方便复用

将属性和方法封装,还有一些私有的属性

私有属性:创建对象后,不能直接访问的属性

  • 私有属性可以在类中的方法访问,外面不能修改

  • 可以保证数据不被污染

  • 公有属性可以被在外面被修改,私有属性不能被修改

python 复制代码
class Body():
    def __init__(self,name,age,money):
        self.name = name
        self.age = age
        self.__money = money # 定义私有属性

    def haha(self):  # 只能在方法里面访问私有属性
        print(f"我是{self.name},钱有{self.__money}")

tom = Body("tom",18,100)
tom.haha()
print(tom.__money)  # 不能在外面进行访问

公有方法:在类的外面可以调用的

私有方法:在类的外面不能进行调用,只能在类里面进行调用

  • 保护了数据的隐私性
python 复制代码
class Body():
    def __init__(self,name,age,money):
        self.name = name
        self.age = age
        self.__money = money # 定义私有属性

    def haha(self):
        print(f"我是{self.name},钱有{self.__money}")
        self.__func()  # 在类的里面进行访问

    def __func(self):   # 定义私有方法
        print("我会飞")

tom = Body("tom",18,100)
tom.haha()

继承(继承复用)

继承;子类继承父类,直接拥有父类的所有属性和方法,不用重复的写代码

如果创建的类没有继承的话,默认继承是object类

作用:减少冗余代码,提高开发效率

就是父类和子类,如果有相同的属性的话,子类不需要再次定义,直接继承父类的属性即可

父类动物,子类:狗,猫,直接继承吃喝睡

python 复制代码
class animal():
    def __init__(self,name,age,sex):
        self.name = name
        self.age = age
        self.sex = sex

    def eat(self):
        print("我可以吃")
    def sleep(self):
        print("我可以睡")


class dog(animal):  # 子类,(继承父类)
    def jiao(self):
        print("汪汪汪")

d1 = dog("tom",18,"male")  # 创建对象
print(d1.name)
d1.eat()  # 可以直接使用父类中的方法
d1.jiao()

重写(灵活)

重写:父类和子类有相同的方法,子类调用的话,使用的就是自己的方法,而不是父类的,子类的优先级高于父类的方法

前提:必须有继承,方法重写

python 复制代码
class animal():
    def __init__(self,name,age,sex):
        self.name = name
        self.age = age
        self.sex = sex

    def eat(self):
        print("我可以吃")
    def sleep(self):
        print("我可以睡")


class dog(animal):
    def eat(self):  # 子类和父类相同的方法,优先使用子类的方法,父类不受影响
        print("我喜欢吃骨头?")

    def jiao(self):
        print("汪汪汪")

d1 = dog("tom",18,"male")
d1.eat()

子类重写后,还想要调用父类的方法,使用super()关键字

python 复制代码
class Haoke():
    def __init__(self,name,age):
        self.name = name
        self.age = age

class Xm(Haoke):
    def __init__(self,name,age,slave):
        self.slave = slave
        super().__init__(name,age)  # 因为重写的原因,子类会使用自己的init方法,但是想要使用父类的init的话,就需要使用super()函数了

    def teach(self):
        print(f"{self.name}我会教代码,我的工资是{self.slave}")

c = Xm("tom",19,"20w")
c.teach()

# 输出为

tom我会教代码,我的工资是20w

多态(灵活)

多态:不同的子类调用同一个父类方法,表现出不同的效果

  • 在函数中,传入不同的类,可以得到不同的状态叫做多态

作用:代码灵活,统一调用,不同的行为

多态经典案例

python 复制代码
# 父类
class Animal:
    def speak(self):  # 这个pass 就是一个抽象类,就是具体怎么实现的方式交给这个不同的子类实现
        pass

# 子类1
class Dog(Animal):
    def speak(self):
        print("汪汪汪")

# 子类2
class Cat(Animal):
    def speak(self):
        print("喵喵喵")

# 统一调用函数
def animal_speak(animal):  # 形参是对象,对象调用方法
    animal.speak()

# 创建对象
dog = Dog()
cat = Cat()

# 同一个方法,不同表现 → 多态
animal_speak(dog)
animal_speak(cat)

不同的动物的叫声不同

其他

使用对象来调用类中属性和方法

一般情况下,我们使用对象来调用属性和方法,而不是使用类来调用

  • 创建多个对象,每个对象都是唯一的

  • self参数本质也是一个对象,因此在方法中,可以使用self.属性名,来使用属性

python 复制代码

类中的属性和方法

属性的本质就是变量

方法的本质就是函数

案例

python 复制代码
# 102kg ,跑一个步减少0.5kg ,吃饭增加1kg

class Xm():
    weight = 102
    def paobu(self):
        self.weight -= 0.5  # self.weight 在还没有创建对象的时候,可以使用这个方式使用,因为self就是对象本身
        print(f"跑步:体重为{self.weight}")
    def eat(self):
        self.weight += 1
        print(f"吃饭:体重为{self.weight}")

tom = Xm()
tom.paobu()
tom.paobu()
tom.eat()
python 复制代码
# 定义一个Hero类 属性有power,name 分别代表体力值和英雄的名字,体力值默认为100,方法有
# (1) 行走的方法,如果体力值为0,则输出不能行走,这个英雄牺牲的信息
# (2) 吃的方法,参数是补充血量,将的n的值加到属性power中,power的最大值为100
# (3) 伤害的方法,每受到一次伤害,体力值-10,体力值最小不能小于0

class Hero():
    power = 100

    def __init__(self,name):
        self.name = name

    def xinzou(self):
        if self.power <= 0:
            print("体力值为0,不能行走")
        else:
            print("可以正常行走")
    def eat(self,n):
        if self.power + n >= 100:
            self.power = 100
            print(f"当前血量已到达上限:{self.power}")
        else:
            self.power += n
            print(f"吃了血包,当前血量为{self.power}")
    def shanghai(self):
        if self.power - 10 < 0:
            self.power = 0  # 血量小于0,就重置血量为0
            print(f"当前体力值为{self.power},已牺牲了")
        else:
            self.power -= 10
            print(f"伤害-10 当前的体力值为{self.power}")

mc = Hero("machao")
mc.shanghai()
mc.shanghai()
mc.eat(10)
mc.xinzou()

总结

类就是一个模板,在这个模板里面定义了很多的参数

然后创建一个对象,调用里面不同的参数,或者修改