Python 基础
2. 继承
2.1 语法角度讲
2.1.1 继承方法
- 代码:
class 父类:
def 父类方法(self):
方法体
class 子类(父类):
def 子类方法(self):
方法体
儿子 = 子类()
儿子.子类方法()
儿子.父类方法()
- 说明:
- 子类直接拥有父类的方法.
2.1.2 内置函数
- isinstance(对象, 类型)
- 返回指定对象是否是某个类的对象。
- issubclass(类型,类型)
- 返回指定类型是否属于某个类型。
"""
继承 - 行为
财产:钱不用孩子挣,但是可以花.
皇位:江山不用太子打,但是可以坐.
代码:子类不用写,但是可以直接用.
"""
class Person:
def say(self):
print("说话")
class Student(Person):
def study(self):
print("学习")
super().say()
def say(self):
print("说")
class Teacher(Person):
def teach(self):
print("教学")
p01 = Person()
# 父类对象,只能访问父类成员
p01.say()
s01 = Student()
# 子类对象,可以访问父类成员和本类成员
s01.say()
# s01.study()
# t01 = Teacher()
# 不能访问兄弟类成员
# t01.study()
# 内置函数
# isinstance 对象 是一种 类型
# 人对象 是一种 人类型
print(isinstance(p01, Person)) # True
# 学生对象 是一种 人类型
print(isinstance(s01, Person)) # True
# 老师对象 是一种 学生类型
print(isinstance(t01, Student)) # False
# 人对象 是一种 老师类型
print(isinstance(p01, Teacher)) # False
# issubclass 类型 是一种 类型
# 人类型 是一种 人类型
print(issubclass(Person, Person)) # True
# # 学生类型 是一种 人类型
print(issubclass(Student, Person)) # True
# # 老师类型 是一种 学生类型
print(issubclass(Teacher, Student)) # False
# # 人类型 是一种 老师类型
print(issubclass(Person, Teacher)) # False
# type 对象 是 类型
# 人对象 是 人类型
print(type(p01) == Person) # True
# 学生对象 是 人类型
print(type(s01) == Person) # False
# 老师对象 是 学生类型
print(type(t01) == Student) # False
# 人对象 是 老师类型
print(type(p01) == Teacher) # False
"""
定义父类
动物(行为:吃)
定义子类
狗(行为:跑)
鸟(行为:飞)
体会isinstance/issubclass/type
"""
class Animal:
def eat(self):
print("吃饭饭喽")
class Dog(Animal):
def run(self):
print("跑喽")
class Bird(Animal):
def fly(self):
print("飞喽")
d01 = Dog()
print(isinstance(d01,Dog))
print(isinstance(d01,Animal))
print(issubclass(Bird,Dog))
print(type(d01))
print(type(d01) == Animal)
2.1.3 继承数据
- 代码
class 子类(父类):
def __init__(self,参数列表):
super().__init__(参数列表)
self.自身实例变量 = 参数
- 说明
- 子类如果没有构造函数,将自动执行父类的,但如果有构造函数将覆盖父类的。此时必须通过super()函数调用父类的构造函数,以确保父类实例变量被正常创建。
2.1.4 定义
- 重用现有类的功能,并在此基础上进行扩展。
- 说明:子类直接具有父类的成员(共性),还可以扩展新功能。
2.1.5 优点
- 一种代码复用的方式。
2.1.6 缺点
- 耦合度高:父类的变化,直接影响子类。
"""
继承 - 数据
"""
class Person:
def __init__(self, name=""):
self.name = name
class Student(Person):
def __init__(self, name="", score=0):
super().__init__(name)
self.score = score
# 如果子类没有构造函数,直接使用父类构造函数
s01 = Student("悟空", 100)
print(s01.name)
"""
定义父类
车(数据:品牌,价格)
定义子类
电动车(数据:充电速度,电池容量)
画出内存图
"""
class Car:
def __init__(self, brand="", price=0):
self.brand = brand
self.price = price
class Electrocar(Car):
def __init__(self, brand="", price=0,
charging_speed=0, battery_capacity=0):
super().__init__(brand, price)
self.charging_speed = charging_speed
self.battery_capacity = battery_capacity
e01 = Electrocar("宝马", 300000, 60, 10000000)
"""
重写:覆盖
子类具有和父类名称相同的方法
调用子类对象时,执行子类方法。(父类方法被覆盖,不执行)
"""
# 对象 --> 字符串
# __str__
class Wife(object):
def __init__(self, name="", age=0):
self.name = name
self.age = age
# 对象 --> 字符串(没有限制)
def __str__(self):
return "奴家%s今年%d岁啦" % (self.name, self.age)
# 对象 --> 字符串(python语法)
def __repr__(self):
return "Wife('%s', %d)"% (self.name, self.age)
w01 = Wife("双儿", 22)
print(w01.name)
content = w01.__str__()
print(content)
code = w01.__repr__()
print(code)
# eval:将字符串作为python代码执行
print(eval("1+2*3"))
# print(eval(input()))
# 克隆对象
w02 = eval(w01.__repr__())
w01.age = 26
print(w02.age,w02.__str__)
2.2 设计角度讲
2.2.1 定义
- 将相关类的共性进行抽象,统一概念,隔离变化。
2.2.2 适用性
- 多个类在概念上是一致的,且需要进行统一的处理。
2.2.3 相关概念
- 父类(基类、超类)、子类(派生类)。
- 父类相对于子类更抽象,范围更宽泛;子类相对于父类更具体,范围更狭小。
- 单继承:父类只有一个(例如 Java,C#)。
- 多继承:父类有多个(例如C++,Python)。
- Object类:任何类都直接或间接继承自 object 类。
"""
设计思想 - 引入
老张开车去东北
变化点:飞机、火车、轮船...
"""
class Person:
def __init__(self, name=""):
self.name = name
def go_to(self, vehicle):
print("走喽")
if type(vehicle) == Car:
vehicle.run()
elif type(vehicle) == Airplane:
vehicle.fly()
class Car:
def run(self):
print("嘟嘟~")
class Airplane:
def fly(self):
print("嗖嗖~")
p01 = Person("老张")
c01 = Car()
a01 = Airplane()
p01.go_to(a01)
"""
设计思想
"""
class Person:
def __init__(self, name=""):
self.name = name
def go_to(self, vehicle):
print("走喽")
# 1. 调用交通工具(父)
if not isinstance(vehicle,Vehicle):
raise Exception("传入的必须是交通工具")
vehicle.transport()
class Vehicle:
"""
交通工具:隔离人与具体交通工具的变化
"""
def transport(self):
pass
# -------------------------------------
class Car(Vehicle):
# 3. 重写
def transport(self):
print("嘟嘟~")
class Airplane(Vehicle):
def transport(self):
print("嗖嗖~")
p01 = Person("老张")
c01 = Car()
a01 = Airplane()
# 2. 创建子类对象
p01.go_to(c01)
3. 多态
3.3 内置可重写函数
- Python中,以双下划线开头、双下划线结尾的是系统定义的成员。我们可以在自定义类中进行重写,从而改变其行为。
3.3.1 转换字符串
- __str__函数:将对象转换为字符串(对人友好的)
- __repr__函数:将对象转换为字符串(解释器可识别的)
3.3.2 运算符重载
- 定义:让自定义的类生成的对象(实例)能够使用运算符进行操作。
3.3.3 算数运算符重载
3.3.4 复合运算符重载
3.3.5 比较运算符重载
"""
运算符重载(重写)
自定义对象使用python运算符
"""
class Vector2:
def __init__(self, x, y):
self.x = x
self.y = y
def __str__(self):
return "x的分量是%d,y的分量是%d" % (self.x, self.y)
# +
def __add__(self, other):
return Vector2(self.x + other.x, self.y + other.y)
# +=
def __iadd__(self, other):
self.x += other.x
self.y += other.y
return self
# <
def __lt__(self, other):
return self.x + self.y < other.x + other.y
# ==
def __eq__(self, other):
return self.x == other.x and self.y == other.y
pos = Vector2(1, 2)
dir = Vector2(0, 1)
# print(pos + dir) # pos.__add__(dir)
# pos.x += dir.x
# pos.y += dir.y
pos += dir
# print(pos)
"""
# 创建了新对象
list01 = [1]
print(id(list01))
list01 = list01 + [2]
print(id(list01))
# 累加(在原有对象基础上增加)
list02 = [1]
print(id(list02))
list02 += [2]
print(id(list02))
"""
list01 = [
Vector2(1, 2),
Vector2(7, 8),
Vector2(5, 6),
Vector2(3, 4)
]
# sorted升序:内部在循环调用每个元素的__lt__
for item in sorted(list01): #
print(item)
#in 的内部也在循环调用每个元素的__eq__方法
print(Vector2(1, 2) in list01)# ?
# list01.remove(Vector2(1, 2))
# list01.count(Vector2(1, 2))
"""
手雷爆炸,伤害玩家(扣血,碎屏)和敌人(扣血,头顶爆字)。
变化点:鸭子,房子...
写出体现三大特征的代码:
封装:根据需求分解出手雷类,玩家类,敌人类
继承:使用攻击目标隔离手雷与玩家,敌人
多态:手雷调用攻击目标,在玩家和敌人对象中体现了不同效果
玩家和敌人分别重写了攻击目标的受伤方法
"""
class Grenade:
def explode(self, target):
target.damage()
class AttackTarget:
def damage(self):
print("扣血")
# ---------------------
class Player(AttackTarget):
def damage(self):
super().damage()
print("碎屏")
class Enemy(AttackTarget):
def damage(self):
super().damage()
print("头顶爆字")
g01 = Grenade()
p01 = Player()
e01 = Enemy()
g01.explode(e01)
四、设计原则
1. 开-闭原则(目标、总的指导思想)
- Open Closed Principle
- 对扩展开放,对修改关闭。
- 增加新功能,不改变原有代码。
2. 类的单一职责(一个类的定义)
- Single Responsibility Principle
- 一个类有且只有一个改变它的原因。
3. 依赖倒置(依赖抽象)
- Dependency Inversion Principle
- 客户端代码(调用的类)尽量依赖(使用)抽象。
- 抽象不应该依赖细节,细节应该依赖抽象。
4. 组合复用原则(复用的最佳实践)
- Composite Reuse Principle
- 如果仅仅为了代码复用优先选择组合复用,而非继承复用。
- 组合的耦合性相对继承低。
5. 里氏替换(继承后的重写,指导继承的设计)
- Liskov Substitution Principle
- 父类出现的地方可以被子类替换,在替换后依然保持原功能。
- 子类要拥有父类的所有功能。
- 子类在重写父类方法时,尽量选择扩展重写,防止改变了功能。
6. 迪米特法则(类与类交互的原则)
- Law of Demeter
- 不要和陌生人说话。
- 类与类交互时,在满足功能要求的基础上,传递的数据量越少越好。因为这样可能降低耦合度。
"""
创建图形管理器:
1. 记录所有图形
2. 计算总面积
图形:
1. 矩形
2. 圆形
...
要求:
增加新图形,管理器代码不变.
画出设计图
写出哪里体现了四大原则
开闭原则:增加新图形,管理器代码不变.
单一职责:Rectanlge负责矩形面积的算法,Circle负责圆形面积的算法,
GraphicManager负责统一管理图形
依赖倒置:图形管理器没有调用圆形、矩形算法,而是调用图形类。
组合复用:图形管理器与具体的各种图形是组合关系。
"""
class GraphicManager:
def __init__(self):
self.__graphics = []
def add_graphic(self, graphic):
self.__graphics.append(graphic)
def calculate_total_area(self):
total_area = 0
for item in self.__graphics:
total_area += item.get_area()
return total_area
class Graphic:
def get_area(self):
pass
# ------------------------
class Rectanlge(Graphic):
def __init__(self, lenght=0, width=0):
self.lenght = lenght
self.width = width
def get_area(self):
return self.lenght * self.width
class Circle(Graphic):
def __init__(self, radius=0):
self.radius = radius
def get_area(self):
return 3.14 * self.radius ** 2
manager = GraphicManager()
manager.add_graphic(Rectanlge(2, 6))
manager.add_graphic(Circle(5))
print(manager.calculate_total_area())
第八章 信息管理系统(*)
一、需求
- 实现对学生信息的增加、删除、修改和查询。
二、分析
界面可能使用控制台,也可能使用Web等等。
-
识别对象:界面视图类 逻辑控制类 数据模型类
-
分配职责:
界面视图类:负责处理界面逻辑,比如显示菜单,获取输入,显示结果等。
逻辑控制类:负责存储学生信息,处理业务逻辑。比如添加、删除等
数据模型类:定义需要处理的数据类型。比如学生信息。 -
建立交互:
界面视图对象 <----> 数据模型对象 <----> 逻辑控制对象
三、设计
- 数据模型类:StudentModel
- 数据:编号 id,姓名 name,年龄 age,成绩 score
- 逻辑控制类:StudentManagerController
- 数据:学生列表 __stu_list
- 行为:获取列表 stu_list,添加学生 add_student,删除学生remove_student,修改学生update_student,根据成绩排序order_by_score。
- 界面视图类:StudentManagerView
- 数据:逻辑控制对象__manager
- 行为:显示菜单__display_menu,选择菜单项__select_menu_item,入口逻辑main,
输入学生__input_students,输出学生__output_students,删除学生__delete_student,修改学生信息__modify_student
"""
步骤一:
数据模型类:StudentModel
数据:姓名 name,年龄 age,成绩 score,编号 id
逻辑控制类:StudentManagerController
数据:学生列表 __stu_list
行为:获取列表 stu_list,
添加学生 add_student
删除学生 remove_student(stu_id)
修改学生 update_student(new_stu)
根据成绩进行升序排列 order_by_score
步骤二:
界面视图类:StudentManagerView
行为:
显示菜单__display_menu,
选择菜单项__select_menu_item,入口逻辑main,
输入学生__input_students,
显示学生信息__output_students
删除学生信息__delete_student
修改学生信息__modify_student
根据成绩升序输出学生__output_students_order_by_score
"""
class StudentModel:
"""
学生数据模型类
"""
def __init__(self, name="", age=0, score=0, id=0):
self.name = name
self.age = age
self.score = score
self.id = id
class StudentManagerController:
"""
学生管理控制器:主要负责业务逻辑处理
"""
init_id = 1000
@classmethod
def __generate_id(cls, stu):
stu.id = cls.init_id
cls.init_id += 1
def __init__(self):
self.__stu_list = []
@property
def stu_list(self):
return self.__stu_list
def add_student(self, stu):
"""
添加学生信息
:param stu: 需要添加的学生对象
"""
StudentManagerController.__generate_id(stu)
self.__stu_list.append(stu)
def remove_student(self, stu_id):
"""
移除学生信息
:param stu_id:需要移除的学生编号
:return:移除是否成功
"""
for item in self.__stu_list:
if item.id == stu_id:
self.__stu_list.remove(item)
return True
return False
def update_student(self, new_stu):
"""
修改学生信息
:param new_stu:需要修改的学生信息
:return:是否修改成功
"""
for item in self.__stu_list:
if item.id == new_stu.id:
item.name = new_stu.name
item.age = new_stu.age
item.score = new_stu.score
return True
return False
def order_by_score(self):
"""
根据成绩升序排列
:return:
"""
for r in range(len(self.__stu_list) - 1):
for c in range(r + 1, len(self.__stu_list)):
if self.__stu_list[r].score > self.__stu_list[c].score:
self.__stu_list[r], self.__stu_list[c] = self.__stu_list[c], self.__stu_list[r]
# 测试
# controller = StudentManagerController()
# data01 = StudentModel("悟空", 23, 96)
# controller.add_student(data01)
# controller.add_student(StudentModel("八戒", 25, 65))
# # print(controller.remove_student(1006))
# # controller.update_student(StudentModel("孙悟空", 24, 97, 1000))
# controller.order_by_score()
# for item in controller.stu_list:
# print(item.id, item.name)
class StudentManagerView:
"""
学生管理视图:主要负责界面逻辑
"""
def __init__(self):
self.__controller = StudentManagerController()
def __display_menu(self):
print("1)添加学生信息")
print("2)显示学生信息")
print("3)删除学生信息")
print("4)修改学生信息")
print("5)根据成绩升序排列")
def __select_menu(self):
item = input("请输入选项:")
if item == "1":
self.__input_students()
elif item == "2":
self.__output_students()
elif item == "3":
self.__delete_student()
elif item == "4":
self.__modify_student()
elif item == "5":
self.__output_students_order_by_score()
def main(self):
"""
程序入口方法
"""
while True:
self.__display_menu()
self.__select_menu()
def __input_students(self):
name = input("请输入学生姓名:")
age = int(input("请输入学生年龄:"))
score = int(input("请输入学生成绩:"))
stu = StudentModel(name, age,score )
self.__controller.add_student(stu)
def __output_students(self):
for item in self.__controller.stu_list:
print("编号是:%d,姓名是%s,年龄是%d,成绩是%d." % (item.id, item.name, item.age, item.score))
def __delete_student(self):
stu_id = int(input("请输入编号:"))
if self.__controller.remove_student(stu_id):
print("删除成功")
else:
print("删除失败")
def __modify_student(self):
stu = StudentModel()
stu.id = int(input("请输入需要修改的学生编号:"))
stu.name = input("请输入需要修改的学生姓名:")
stu.age = int(input("请输入需要修改的学生年龄:"))
stu.score = int(input("请输入需要修改的学生成绩:"))
if self.__controller.update_student(stu):
print("修改成功")
else:
print("修改失败")
def __output_students_order_by_score(self):
self.__controller.order_by_score()
self.__output_students()
view = StudentManagerView()
view.main()