目录:
创作不易,各位看官,点个赞收藏、关注必回关、QAQ、您的点赞是我更新的最大动力!
一、封装
(一)什么是封装
封装,是面向对象的第一个特性,体现了对数据的有效组织和数据安全性的保护机制, 在传统的编码中,面向对象编程思想中的类型体现的是对数据的描述,而对象体现的则是个 体数据的展示,既然是个体数据反映的就是生活中的私有数据,就需要考虑其访问安全性, 反应到生活中就是每个个体私有数据的保护,如图所示:
(二)封装的基本语法
1、所有属性私有化
python 语言在实现封装时,一些项目规范中约定使用一个下划线开头的属性为当前对象私 有属性,不允许外界访问,但是一个下划线开头的属性是可以被直接访问的。 |
语法上两个下划线开头的属性或者方法,在外界是不允许直接访问的。 |
语法上两个下划线开头并且结尾的属性有特殊的应用场合。 |
class Manager:
"""管理员类型"""
def __init__(self, username, password, nickname, email, phone):
"""初始化属性数据:所有属性私有化"""
self.__username = username # 标准的私有化语法
self.__password = password # 标准的私有化语法
self.__nickname = nickname # 标准的私有化语法
2、访问私有属性
属性私有化之后,给每个属性提供访问属性的 get 方法和设置赋值的 set 方法,通过固 定语法的格式提供给对象外部的调用者
- 一般访问 str
#属性私有化之前,用户信息可以直接访问并修改
class User:
"""用户类型"""
def __init__(self,name,age):
"""用户姓名和年龄"""
self.name = name
self.age = age
def __str__(self):
"""打印用户信息"""
return f"我叫{self.name},今年{self.age}岁"
user = User("小明",23)
print(user)
- 使用setter和getter访问
def set__username(self, username):
"""给私有属性设置数据的方法"""
self.__username = username
def get__username(self):
"""获取私有属性数据的方法"""
return self.__username
- 使用限定条件访问
作用:就是在开发过程中保护核心代码,在类的外部不能使用(对象不能调用私有方法)
3、私有方法
class A:
def __test1(self):
print("--in test1--")
def test2(self):
self.__test1()
print("--in test2--")
a = A()
# a.__test1() #对象不能调用私有方法
a.test2()
4、私有属性修改
class User:
"""用户类型"""
def __init__(self,name,age):
"""用户姓名和年龄"""
# self.name = name
# self.age = age
self.__name = name
self.__age = age
def __str__(self):
"""打印用户信息"""
# return f"我叫{self.name},今年{self.age}岁"
return f"我叫{self.__name},今年{self.__age}岁"
user = User("小明",23)
# print(user)
#属性私有化之前,对象的属性如下
# print(user.__dict__) #{'name': '小明', 'age': 23}
# user.name = "稳稳" #可以修改
#属性私有化之后,对象的属性如下
print(user.__dict__) #{'_User__name': '小明', '_User__age': 23}
# user.__name = "稳稳" #只是增加属性
# print(user.__dict__)
user._User__name = "稳稳"
print(user)
二、继承
(一)什么是继承让类与类之间产生父子关系,子类可以拥有父类的属性和方法(私有属性和私有方法无法继承)
父类 | 用于被继承的类,称为父类,也叫基类,或者超类 |
子类 | 继承其它类的类,称为子类,也叫派生类 |
查看继承父类的 | _ base_() |
继承的作用: 可以提高代码的复用率
(二)继承的基本语法
"""
继承的基本语法
父类:被继承的类型,需要重复利用的代码包含在父类中
子类:当前类型,继承其他类型,重复使用其他类型中的代码
python中的所有类型都是直接或者间接继承自object
都是从object派生出来的!
子类继承父类,父类派生子类!
"""
class Father:
"""父亲类型"""
def __init__(self, name, gender, age):
self.name = name
self.gender = gender
self.age = age
def sleep(self):
print("睡觉时间到了,准备午休..")
def study(self):
print("充电时间到了,准备学习..")
class Son(Father):
"""儿子类型:继承父亲类型"""
pass
tom = Son("汤姆", "男", 18)
print(tom.name, tom.age, tom.gender)
tom.study()
tom.sleep()
复用性体现 [使用父类的属性]:
"""
继承中父类的代码的复用
"""
class Animal:
"""动物类型"""
def __init__(self, nickname, amtype):
self.nickname = nickname
self.amtype = amtype
def move(self):
print("某个动物在运动中...")
class Beast(Animal):
"""地上跑的"""
pass
class Bird(Animal):
"""天上飞的"""
pass
class Fish(Animal):
"""水里游的"""
pass
cat = Beast("汤姆猫", "走兽")
beita = Bird("开飞机的贝塔", "飞禽")
xiaolu = Fish("水里的美人鱼", "游鱼")
cat.move()
beita.move()
xiaolu.move()
复用性高级[使用父类的属性,自己定义自己的属性]:
"""
继承中父类的代码的复用升级
从一个问题说起:
直接使用父类不好吗?为什么要写那么多子类的空代码?
灵机一动:难道为了一行代码一块钱?
① 通过子类继承父类
子类能更好的更精确的描述生活中的某个对象
猫 = 动物()
猫 = 走兽() 更加准确
② 通过子类继承父类
子类在复用父类代码的情况下,能扩展自己的属性
父类的每个子类,都有互相不同的地方~
所以才将多个子类相同的代码声明在父类中复用
子类中互不相同的代码保留在自己子类中使用
"""
class Animal:
"""动物类型"""
def __init__(self, nickname, amtype):
self.nickname = nickname
self.amtype = amtype
def move(self):
print("某个动物在运动中...")
class Beast(Animal):
"""地上跑的"""
def __init__(self, nickname, amtype, blood):
# 子类如果一旦编写__init__()方法
# 就必须显式的调用父类的__init__()方法初始化父类数据
# Animal.__init__(nickname, amtype)
# super(Beast, self).__init__(nickname, amtype)
# ① 复用父类的代码
super().__init__(nickname, amtype)
# ② 子类自己的代码
self.blood = blood
class Bird(Animal):
"""天上飞的"""
def __init__(self, nickname, amtype, attact):
# ① 复用父类的代码
super().__init__(nickname, amtype)
# ② 子类独有的代码
self.attact = attact
class Fish(Animal):
"""水里游的"""
pass
cat = Beast("汤姆猫", "走兽", 2000)
beita = Bird("开飞机的贝塔", "飞禽", 100)
xiaolu = Fish("水里的美人鱼", "游鱼")
print(cat.nickname, cat.amtype, cat.blood)
print(beita.nickname, beita.amtype, beita.attact)
cat.move()
beita.move()
xiaolu.move()
(三)方法覆盖 [重写]
简单的来说,就是将父类里面的方法,在子类里面重写
"""
方法重载:
子类中声明和定义了父类中相同名称和参数的方法
"""
class Animal:
"""动物类型"""
def __init__(self, nickname):
self.nickname = nickname
def move(self):
print(f"{self.nickname}在移动中..")
class Beast(Animal):
"""走兽"""
def move(self):
print(f"{self.nickname}在快速的奔跑中..")
class Bird(Animal):
"""飞禽"""
def move(self):
print(f"{self.nickname}在愉快的飞行中..")
class Fish:
"""游鱼"""
def __init__(self, nickname):
self.nickname = nickname
def swimming(self):
"""移动的方法"""
print("飞快的游走中...")
cat = Beast("汤姆猫")
shuke = Bird("舒克的飞机")
# 调用的是同一个方法,但是执行的是不同的结果
cat.move() # 汤姆猫在快速的奔跑中..
shuke.move() # 舒克的飞机在愉快的飞行中..
xiaolu = Fish("小鹿")
xiaolu.swimming()
'''
通过方法重写
① 理解继承的代码的重用型
② 继承关系中,对于子类中的代码有了一定的约束性
③ 方法覆盖,体现了一种运行时状态改变-体现了多态
如果子类没有重写父类的方法,就直接执行父类的方法
如果子类重写了父类的方法,就执行子类重写后的方法
'''
(四)子类访问父类 [使用父类中的super()方法,三种方法]
坦克大战:
"""
方法重载案例:坦克大战中的坦克
"""
class Tank:
"""坦克类型"""
def fire(self):
print("坦克开火了,发射子弹(10行代码)...")
class HeroTank(Tank):
"""英雄坦克:玩家控制"""
def fire(self):
# 子类中额外添加的功能
print("英雄坦克,模拟玩家按下空格键,发射子弹[事件(按下空格动作)操作]")
# 复用父类中发射子弹的代码
# Tank.fire(self) #1.父类名.方法名(self)
# super(Tank,self).fire() #2.super(当前类名,self).方法名()
super().fire() #3.super().fire()
class EnemyTank(Tank):
"""敌方坦克:电脑控制"""
def fire(self):
print("添加代码,控制坦克间隔随机时间发射子弹")
super().fire()
hero = HeroTank()
hero.fire()
enemy = EnemyTank()
enemy.fire()
综合案例-宠物医院:
"""
宠物医院案例
面向对象开发
"""
import time
class Pet:
"""宠物父类"""
def __init__(self, nickname, health):
self.nickname = nickname # 昵称
self.health = health # 健康状态[0~30病危|30-60生病|60-80亚健康|80-100健康]
def recovery(self):
"""康复的行为"""
while self.health <= 65:
self.health += 5
time.sleep(0.5)
print(f"{self.health}>>正在恢复中.....")
class Hospital:
"""宠物医院"""
def __init__(self, name):
self.name = name
def care(self, pet):
"""治疗的行为"""
# 判断某个对象是否属于某种类型:判断pet对象是否Pet类型
if isinstance(pet, Pet):
# 医院开始治疗,用药
print(f"开始治疗{pet.nickname}")
# 宠物开始恢复
pet.recovery()
else:
print("宠物医院只接受宠物进行治疗....")
class Cat(Pet):
"""宠物猫"""
pass
class Dog(Pet):
"""宠物狗"""
pass
class Person:
def __init__(self, nickname, health):
self.nickname = nickname
self.health = health
def recovery(self):
while self.health <= 60:
self.health += 20
print("正在快速的恢复中...")
hospital = Hospital("玛利亚宠物医院")
# cat = Cat("汤姆猫", 30)
# hospital.care(cat)
# print("最终宠物的健康值:", cat.health)
dog = Dog("二哈", 20)
hospital.care(dog)
print("最终二哈的健康值:", dog.health)
# damu = Person("大牧", 50)
# hospital.care(damu)
(五)多继承 [隔代继承]
1、基本语法
python 语法中提供了多继承的语法,用于体现生活中一个对象多种角色的情况,具体 语法上是将多个继承的类型依次写在子类声明后面的括号中
隔代继承:
class Animal:
def __init__(self):
print("我是动物")
class dog(Animal):
pass
class cat(dog):
pass
#创建对象
cat_tom = cat() #输出 “我是动物”
多继承:
"""
多继承关系
多继承需要注意的问题:如果多个父类中出现了相同名称的属性、方法怎么办?
"""
class Son:
"""儿子类型"""
def respect(self):
"""尊敬,孝顺"""
print("百善孝为先")
def play(self):
print("作为儿子角色,越快的玩耍中...")
class Husband:
"""丈夫类型"""
def love(self):
"""恩爱的行为"""
print("相濡以沫")
def play(self):
print("作为丈夫的角色,王者荣耀中...")
class Father:
"""老爹类型"""
def care(self):
"""爱护的行为"""
print("家里的千金,万般呵护..")
class Teacher:
"""老师类型"""
def teach(self):
"""授课的行为"""
print("前人栽树....")
class Person(Son, Husband, Father, Teacher):
"""人的类型"""
pass
# def play(self):
# print("Person 愉快的玩耍中...")
wenwen = Person()
wenwen.play() # Son, Husband
# # 儿子
# if isinstance(wenwen, Son):
# wenwen.respect()
#
# # 丈夫
# if isinstance(wenwen, Husband):
# wenwen.love()
#
# # 父亲
# if isinstance(wenwen, Father):
# wenwen.care()
#
# # 老师
# if isinstance(damu, Teacher):
# wenwen.teach()
2、注意事项
多继承关系中,一个类型继承多个类型,如果在继承的多个类型中出现了相同名称的属 性或者方法(当然如果出现一般都是软件结构设计上存在问题),就会出现子类如果使用到了 这样的属性和方法,优先调用的是继承的那个类型的属性或者方法了 上述问题如果一旦出现,有两种解决方案:
- 重新设计软件架构,对类型中的属性进行规范整理
- 梳理调用顺序,按照语法语义上的顺序执行
运行程序只看输出“动物的爱”
第一种方案如果一旦实施就是常规编程,第二种方案中确定某个重复声明的属性的查询 顺序,可以通过规范语法进行确定,Python 提供了 mro() 方法用于确定继承关系中属性和方 法的查询操作顺序
class Animal:
"""动物类型"""
def love(self):
print("动物的爱")
class Person:
"""人的类型"""
def love(self):
print("人的爱")
class Tom(Animal,Person):
pass
user_Tom = Tom()
user_Tom.love()
print(Tom.mro())
3、属性查询顺序
Python3 中已经改善了 Python2 中多种类型操作方式(Python2/3 的区别在十五讲会详细 说明),统一了类型的声明和加载方式,对于多继承中的重名属性和重名方法的查询执行顺 序,使用了广度优先的查询原则
(六)___init()___
这边其实方法重写已经提到过了
所以这边就简单复述下
- 继__init() __构建对象后属性初始化的方法
- 双下划线开头结尾称为魔法方法
- 魔法方法只会继 承固定语法格式,如果在子类中改变了原有的语法格式的情况下,一定要主动调用父类相同 的方法初始化,否则会出现父类数据没有初始化的问题
如果子类中没有编写__init__()方法,创建对象时就会自动执行继承的默认的无参数的 init()方法,并且自动调用父类的__init__()完成初始化过程,如果所示:
如果子类中一旦编写了自定义了__init__()方法,默认继承的空参数的__init__()就会失效, 必须显式的主动的调用父类的__init__()方法完成父类初始化工作,否则父类的数据就不会被 正确的继承过来了
三、多态
(一)什么是多态?多态是程序运行过程中,根据运行时的数据的差异,产生不同的处理状态,运行不同的 逻辑代码的过程 多态作为面向对象的特征之一,没有固定的语法,在经典的程序设计模式中有多种体现 方式,如策略模式中就可以根据传递的具体执行方案执行对应的处理结果
多态基本案例:
# 定义人类:可以调速,可以玩,在玩的过程中跳舞
# 实现多态:老年人跳广场舞
# 多态三个条件
"""
1.必须存在继承关系
2.重写目标方法
3.使用子类对象调用父类方法
"""
class Person:
"""人的类型"""
def danc(self):
print("跳舞")
def play(self): # self = old 老年人
self.danc()# 老年人调用跳舞,本人含义跳舞
class OldMan(Person):
"""老年人类型"""
def danc(self):
print("跳广场舞")
#
# # per1 = Person()
# # per1.play()
old = OldMan()
old.play()
策略模式
图示中用户需要在某网站上注册账号,网站动态判断用户的注册方式并响应验证 码给正确的终端设备,在开发过程中函数式编程可以直接进行判断处理,但是不利于程序功 能的扩展(大家可以编写函数式的实现方式进行尝试)。通过策略模式进行完成上述功能流程, 同时还为将来功能的扩展预留了空间
"""
网站可以注册,注册有默认的验证码发送方式
分析:
网站类
方法:注册方法,调用默认设备,发送验证码
设备类
方法:生成验证码并发送
策略模式
"""
class WebSite:
"""网站类型"""
def register(self,device):
print("开始注册")
#调用设备发送验证码的方法
device.send("6666")
input("验证码已发送,请输入")
print("注册成功")
class Device:
"""设备类型"""
def send(self,code):
print("默认发送验证码:",code)
class Phone(Device):
"""手机注册"""
def send(self,code):
print("通过手机发送验证码: ",code)
class Email(Device):
"""邮箱注册"""
def send(self, code):
print("通过手机发送验证码: ", code)
# 1 网页注册
# # 用户注册
# ws = WebSite()
# device = Device()
# # 发起注册
# ws.register(device)
# 2 手机注册
# 用户注册
ws = WebSite() # 创建对象
phone = Phone() # 实例化设备对象
# 发起注册
ws.register(phone)
四、综合案例
"""
学生选课管理系统
管理员,添加课程,查看课程 [,删除课程,修改课程]
宗澄:课程保存课程说不通
业务受理:增加课程,,管理员增加课程 add_course()
逻辑处理:增删改查数据-- 保存数据-- 课程对象~保存自己的数据 save()
"""
class Database:
"""数据库类型:存储项目中的所有数据"""
# 类属性:存储课程-- key课程名称:value课程对象
courses_dict = dict()
class Users:
"""学生选课管理系统 用户类型"""
def __init__(self, username, password, nickname, email, phone):
"""初始化属性数据"""
self.username = username
self.password = password
self.nickname = nickname
self.email = email
self.phone = phone
class Manager(Users):
"""管理员类型"""
def add_course(self):
"""增加课程的方法"""
name = input("请输入课程名称:")
if name in Database.courses_dict:
print("课程已经存在,请使用其他名称添加")
return self.add_course()
teacher = input("请输入授课老师:")
maxsize = input("请输入人数上限:")
times = input("请输入课程课时:")
score = input("请输入课程学分:")
desc = input("请输入课程描述:")
# 创建课程对象
course = Course(name, teacher, maxsize, times, score, desc)
# 保存课程数据
course.save()
input("课程添加完成,按任意键继续。")
def check_course(self):
"""查询课程的方法"""
# TODO 待完善
for name, course in Database.courses_dict.items():
print(f"课程名称:{name}, 课程:{course}")
input("课程查看完成,按任意键继续")
def update_course(self):
"""修改课程信息的方法"""
name = input("请输入课程名称:")
if name not in Database.courses_dict:
print("课程不存在,请重新输入")
return self.update_course()
# 获取到要修改的课程数据
course = Database.courses_dict.get(name)
# 修改数据
teacher = input("请输入授课老师:")
maxsize = input("请输入人数上限:")
times = input("请输入课程课时:")
score = input("请输入课程学分:")
desc = input("请输入课程描述:")
# 保存课程数据
course.update()
input("课程修改完成,按任意键继续。")
def delete_course(self):
"""删除课程的方法"""
name = input("请输入要删除的课程名称:")
if name not in Database.courses_dict:
print("要删除的课程不存在,按任意键重新输入")
return self.delete_course()
# 直接删除课程:直接从字典中根据课程key删除了键值对
Database.courses_dict.pop(name)
input("课程删除完成,按任意键继续。")
class Course:
"""课程类型"""
def __init__(self, name, teacher, maxsize, times, score, desc):
self.name = name # 课程名称
self.teacher = teacher # 授课老师
self.maxsize = maxsize # 选择人数限制
self.times = times # 授课课时
self.score = score # 课程学分
self.desc = desc # 课程描述
def save(self):
"""保存课程数据"""
Database.courses_dict[self.name] = self
def update(self):
"""修改课程数据"""
# 重新保存数据时,因为key没有变化,所以新的数据会覆盖旧的数据
self.save()
def delete(self):
"""删除课程"""
# 通过key删除字典中的一个键值对
Database.courses_dict.pop(self.name)
def __str__(self):
return f"课程[名称:{self.name}, 老师:{self.teacher},描述:{self.desc}]"
# 创建管理员对象
manager = Manager("wenwen", "123", "稳稳", "[email protected]", "15666666666")
# 添加课程
manager.add_course()
# 查看课程
manager.check_course()