面向对象和面向过程 这个是非常重要的编程思想
面向过程和面向对象
面向过程和面向对象是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()
总结
类就是一个模板,在这个模板里面定义了很多的参数
然后创建一个对象,调用里面不同的参数,或者修改