P130 多态练习题(1)2025/2/21
一、isinstance函数
- 基本说明:
isinstance()
用于判断对象是否为某个类或其子类的对象- 基本语法:
isinstance(object,classinfo)
- 解读形参:
object
:对象
classinfo
:可以是类名、基本类型或者由它们组成的元组
- 实例演示:
# @Author :ZH_JC
# @File :20_isinstance_example.py
# @Time :2025/2/21 14:01
class AA:
pass
class BB(AA):
pass
class CC:
pass
# 创建两个对象
obj = BB()
obj2 = AA()
# 分析输出的结果
print(f"obj 是不是BB的对象 {isinstance(obj, BB)}") # T
print(f"obj 是不是AA的对象 {isinstance(obj, AA)}") # T
print(f"obj 是不是CC的对象{isinstance(obj, CC)}") # F
num = 9
print(f"num 是不是int:{isinstance(num, int)}") # T
print(f"num 是不是str:{isinstance(num, str)}") # F
# 是元组中的一个返回 True
print(f"num 是不是str/int/list:{isinstance(num, (str, int, list))}") # T
二、练习题
- 代码阅读题,看下面的代码,分析输出内容是什么?
# @Author :ZH_JC
# @File :21_poly_exercise01.py
# @Time :2025/2/21 14:11
class A:
i = 10
def sum(self):
return self.getI()+ 10
def sum1(self):
return self.i + 10
def getI(self):
return self.i
class B(A):
i= 20
def sum(self):
return self.i + 20
def getI(self):
return self.i
b = B()
print(b.sum()) # 输出什么? 40
print(b.sum1()) # 输出什么 30
- 对上面的代码做修改(将B中sum注释),分析输出内容是什么?
- 知识点:当调用用对象成员的时候,会和对象本身动态关联
class A:
i = 10
def sum(self):
# 这里的self是A还是B 【B】
# 当调用用对象成员的时候,会和对象本身动态关联;所以会调用B里面的getI
return self.getI()+ 10
def sum1(self):
# 这里B传进来依然是B里面的i
return self.i + 10
def getI(self):
return self.i
class B(A):
i= 20
# def sum(self):
# return self.i + 20
def getI(self):
return self.i
b = B()
print(b.sum()) # 输出什么?-->30
print(b.sum1()) # 输出什么---> 30
P131 多态练习题(2)2025/2/22
一、练习题
编程题:
- 定义员工类
Employee
,包含私有属性(姓名和月工资),以及计算年工资get_annual
的方法- 普通员工
(Worker)
和经理(Manager)
继承员工类,经理类多了奖金bonus属性和管理manage方法,普通员工类多了work方法,普通员工和经理类要求根据需要重写get_annual
方法- 编写函数
show_emp_annual(e:Employee)
,实现获取任何员工对象的年工资- 编写函数
working(e:Emplovee)
,如果是普通员工,则调用work方法,如果是经理,则调用manage方法
# @Author :ZH_JC
# @File :22_poly_exercise02.py
# @Time :2025/2/22 15:05
# 3、编程题(文件:poly_exercise_02.py)5min
# 1)定义员工类Employee,包含私有属性(姓名和月工资),以及计算年工资get_annual的方法
# 2)普通员工(Worker)和经理(Manager)继承员工类,经理类多了奖金bonus属性和管理manage方法,普通员工
# 类多了work方法,普通员工和经理类要求根据需要重写get annual方法
# 3)编写函数show_emp_annual(e:Employee),实现获取任何员工对象的年工资
# 4)编写函数working(e:Emplovee),如果是普通员工,则调用work方法,如果是经理,则调用manage方法
class Employee:
__name = None
__salary = None
# 构造器
def __init__(self, name, salary):
self.__name = name
self.__salary = salary
# 计算年工资的方法
def get_annual(self):
return self.__salary * 12
# 编写set_xxx和get_xxx方法
def set_name(self, name):
self.__name = name
def get_name(self):
return self.__name
def set_salary(self, salary):
self.__salary = salary
def get_salary(self):
return self.__salary
# 子类Worker
class Worker(Employee):
def work(self):
print(f"普通工人{self.get_name()} 正在工作...")
# 子类Manager
class Manager(Employee):
__bonus = None
def __init__(self, name, salary, bonus):
super().__init__(name, salary)
self.__bonus = bonus
def manager(self):
print(f"经理{self.get_name()} 正在管理...")
# 根据需要,经理有奖金,需要重写get_annual
def get_annual(self):
# 这里必须使用super()调用父类annual,因为本类有了get_annual,否则会递归
return super().get_annual() + self.__bonus
# 3)编写函数show_emp_annual(e:Employee),实现获取任何员工对象的年工资
def show_emp_annual(e: Employee):
print(f"{e.get_name()}的年工资是{e.get_annual()}")
# 测试
worker = Worker("king", 10000)
show_emp_annual(worker)
manager = Manager("tim", 20000, 100000)
show_emp_annual(manager)
# 4)编写函数working(e:Emplovee),如果是普通员工,则调用work方法,如果是经理,则调用manage方法
def working(e: Employee):
# 如果是普通员工
if isinstance(e, Worker):
e.work()
elif isinstance(e, Manager):
e.manager()
else:
print("无法确定工作状态")
working(worker)
working(manager)
总结:又涉及了封装继承和多态
P132 魔术方法 2025/2/22
- 参考文档:https://docs.python.org/zh-cn/3.12/reference/datamodel.html?highlight=_%20ne#basic-customization
一、基本介绍
- 什么是魔术方法:
- 在Python中,所有以双下划线包起来的方法,统称为
Magic Method
(魔术方法),它是一种的特殊方法,普通方法需要调用,而魔术方法不需要调用就可以自动执行。 - 魔术方法在类或对象的某些事件发生时会自动执行,让类具有神奇的"魔力"。如果希望根据自己的程序定制特殊功能的类,那么就需要对这些方法进行重写。
- Python中常用的运算符、for循环、以及类操作等都是运行在魔术方法之上的。
- 常见的魔术方法:
二、常见魔术方法
- 1、
__str__
基本介绍:
- 打印对象默认返回:类型名+对象内存地址【演示】,子类往往重写
__str__
,用于返回对象的属性信息
main__.Person object at 0x0000019314BC7C90>
- 重写
__str__
方法,print(对象)或str(对象)时,都会自动调用该对象的__str__
# @Author :ZH_JC # @File :23_str_magic_method.py # @Time :2025/2/22 17:32 class Monster: name = None age = None gender = None def __init__(self, name, age, gender): self.name = name self.age = age self.gender = gender # 请输出Monster[name,job,sal]对象的属性信息 # 可以根据需要重写__str__ :(如果不重写就是调用父类str的方法) """ 说明: 1. 在默认情况下,调用的是父类object的__str__ 2. 父类object的__str__返回的就是类型+地址 3. __str___可以根据需要重写 """ def __str__(self): return f"{self.name} {self.age} {self.gender}" m = Monster("青牛怪", 500, "男") # print(m,hex(id(m))) print(m) # 默认输出类型+对象的地址
- 2、
__eq__
基本介绍:
==
是一个比较运算符:对象之间进行比较时,比较的是内存地址是否相等,即判断是不是同一个对象- 重写
__eq__
方法,可以用于判断对象内容/属性是否相等
- 应用实例:
1)判断两个Person对象的内容是否相等,如果两个Person对象的各个属性值都一样,则返回true,反之false
2)Person类,属性(name,age,gender)# @Author :ZH_JC # @File :24_eq_magic_method.py # @Time :2025/2/22 19:06 class Dog: def __init__(self, name, age, gender): self.name = name self.age = age self.gender = gender class Person: def __init__(self, name, age, gender): self.name = name self.age = age self.gender = gender # 判断两个Person对象的内容是否相等,如果两个Person对象的各个属性值都一样, # 则返回true,反之false def __eq__(self, other): # other 相当于比较时的p2 # 判断other是不是Person (人和狗比不合理,不正常比较) if isinstance(other, Person): return (self.name == other.name and self.age == other.age and self.gender == other.gender) return False # 没有重写 __eq__ 前,== 比较的是内存地址,返回F,重写后返回T p1 = Person("smith", 20, "男") p2 = Person("smith", 21, "男") dog = Dog("smith", 20, "男") # ==比较的是内存地址,所以返回的是False print(f"p1==p2: {p1 == p2}") # F print(f"p1==dog: {p1 == dog}") # F
三、其他魔术方法
- 应用实例:
- 根据Person对象的年龄进行比较大小,重写相应的魔术方法
- Person类,属性
(name,age,gender
class Person:
def __init__(self, name, age, gender):
self.name = name
self.age = age
self.gender = gender
# 判断两个Person对象的内容是否相等,如果两个Person对象的各个属性值都一样,
# 则返回true,反之false
def __eq__(self, other): # other 相当于比较时的p2
# 判断other是不是Person (人和狗比不合理,不正常比较)
if isinstance(other, Person):
return (self.name == other.name and
self.age == other.age and
self.gender == other.gender)
return False
# 重写__lt__
def __lt__(self,other):
# 判断other是不是Person (人和狗比不合理,不正常比较)
if isinstance(other, Person):
return self.age < other.age
return "类型不一致"
# 重写__le__
def __le__(self,other):
# 判断other是不是Person (人和狗比不合理,不正常比较)
if isinstance(other, Person):
return self.age <= other.age
return "类型不一致"
def __ne__(self, other): # other 相当于比较时的p2
return not self.__eq__(other)
# 没有重写 __eq__ 前,== 比较的是内存地址,重写是比较属性内容
p1 = Person("smith", 21, "男")
p2 = Person("smith", 21, "男")
dog = Dog("smith", 20, "男")
# ==比较的是内存地址,所以返回的是False
print(f"p1==p2: {p1 == p2}")
print(f"p1==dog: {p1 == dog}")
print(f"p1 < p2:{p1 < p2}")
print(f"p1 < p2:{p1 <= p2}")
print(f"p1 < p2:{p1 != p2}")
P133 class对象和静态方法 2025/3/2
一、基本介绍
参考文档:https://docs.python.org/zh-cn/3.11/tutorial/classes.html#instance-objects
类本身也是对象,即:
Class对象
案例演示:
# @Author :zjc
# @File :25_class_object.py
# @Time :2025/3/2 20:51
class Monster:
name = "蝎子精"
age = 300
def hi(self):
print(f"hi() {self.name}-{self.age} ")
# 下一个断点,可以看到Monster的情况
print(Monster)
# 通过Class对象,可以引用属性〔没有创建实例对象也可以引用/访问)
print(f"Monster.name: {Monster.name} Monster.age:{Monster.age}")
# 通过类名如何调用非静态成员方法.(类本身就是对象),通过类名也可以调用成员方法
Monster.hi(Monster)
二、静态方法
基本介绍:
- 参考文档:https://docs.python.org/zh-cn/3.12/library/functions.html#staticmethod
3. @staticmethod
将方法转换为静态方法
4. 静态方法不会接收隐式的第一个参数,要声明一个静态方法,语法:
class c:
@staticmethod
def f(arg1, arg2, argN): ...
- 静态方法既可以由类调用(如
C.f())
,也可以由实例中调用(如C().f()
)
# @Author :zjc
# @File :26_staticmethod.py
# @Time :2025/3/2 21:17
class Monster:
name = "蝎子精"
age = 300
def hi(self):
print(f"hi() {self.name}-{self.age} ")
@staticmethod
def ok():
print(f"ok()... ")
# 不需要实例化,通过类即可调用静态方法
Monster.ok()
# 通过实例对象,也可以调用静态方法
monster = Monster()
monster.ok()
# 这样调用也是一样的
Monster().ok()
P134 抽象类快速入门 2025/3/3
一、问题引出
- 有行为,但是不明确。
class Animal:
def __init__(self, name, age):
self.name = name
self.age = age
def cry(self):
"""
动物都有叫唤的行为...但是这个行为不明确(即不能明确的实现..):
:return:
"""
print("不知道是什么动物,不知道是什么叫声...")
- 需求:
- 当父类的某些方法,需要声明,但是又不确定如何实现时,怎么办?
- 不需要实例化父类对象,父类主要的是用于设计和制定规范,让其它类来继承并实现,怎么办?
- 解决方案->抽象类
二、抽象类介绍
- 默认情况下,Python不提供抽象类,Python附带一个模块,该模块为定义抽象基类提供了基础,该模块名称为abc
- 当我们需要抽象基类时,让类继承ABC(abc模块的ABC类),使用
@abstractmethod
声明抽象方法(@abstractmethod
用于声明抽象方法的装饰器,在abc模块中),那么这个类就是抽象类 - 抽象类的价值更多作用是在于设计,是设计者设计好后,让子类继承并实现抽象类的抽象方法
三、快速入门
- 参考文档:https://docs.python.org/zh-cn/3.12/library/abc.html#abstractmetho、
- 当父类的一些方法不能确定时,可以使用
@abstractmethod
声明(说明:@abstractmethod
用于声明抽象方法的装饰器),同时继承ABC类,那么这个类就是抽象类 - 案例演示:我们看看如何把Animal做成抽象类,并让子类Tiger实现
# @Author :zjc
# @File :27_abstract_quick_start.py
# @Time :2025/3/3 14:22
# 导入abc模块中的ABC类
from abc import ABC, abstractmethod
# 把Animal做成抽象类,并让子类Tiger实现
# Animal就是抽象类
class Animal(ABC):
def __init__(self, name, age):
self.name = name
self.age = age
# 这时:cry就是一个抽象方法
@abstractmethod
def cry(self):
# """
# 动物都有叫唤的行为...但是这个行为不明确(即不能明确的实现..):
# :return:
# """
# print("不知道是什么动物,不知道是什么叫声...")
pass
# 注意:抽象类(含有抽象方法),不能实例化
# TypeError: Can't instantiate abstract class Animal
# animal = Animal("动物",3)
# 编写子类Tiger 继承Animal 并实现抽象方法
class Tiger(Animal):
def cry(self):
print(f"老虎{self.name} 嗷嗷")
# 因为Tiger继承了Animal,这里可以使用Animal的构造器
tiger = Tiger("皮皮", 2)
tiger.cry()
P135 抽象类细节和练习 2025/3/3
一、注意事项和细节
- 抽象类不能被实例化
- 抽象类需要继承ABC,并且需要至少一个抽象方法
# 抽象类需要继承ABC,并且需要至少一个抽象方法
from abc import ABC, abstractmethod
class AAA(ABC):
name = "tim"
# 如果有一个抽象方法是不能被实例化的
@abstractmethod
def f1(self):
pass
#如果没有一个抽象方法,能实例化..
obj1 = AAA()
print( "ok")
- 抽象类中可以有普通方法
from abc import ABC, abstractmethod
class AAA(ABC):
name = "tim"
@abstractmethod
def f1(self):
pass
def hi(self):
print("hi()~~")
def ok(self):
pass
class BBB(AAA):
# 实现父类的f1抽象方法
def f1(self):
print("BBB-f1()...")
# 全部执行成功说明,抽象类中可以有普通方法
obj2 = BBB()
obj2.f1()
obj2.hi()
obj2.ok()
print("~~~")
- 如果一个类继承了抽象类,则它必须实现抽象类的所有抽象方法,否则它仍然是一个抽象类
from abc import ABC, abstractmethod
class AAA(ABC):
name = "tim"
@abstractmethod
def f1(self):
pass
@abstractmethod
def f2(self):
pass
def hi(self):
print("hi()...")
def ok(self):
pass
class BBB(AAA):
# 实现父类的f1抽象方法
def f1(self):
print("BBB-f1()...")
# 如果没有完全实现AAA的抽象方法,则会报错
# TypeError: Can't instantiate abstract class
def f2(self):
print("BBB-f2()...")
obj2 = BBB()
obj2.f1()
obj2.hi()
obj2.ok()
print("~~~")
二、练习题
- 代码:
# @Author :zjc
# @File :29_abstract_exercise.py
# @Time :2025/3/3 15:38
"""
1)编写一个Employee类,做成抽象基类,包含如下三个属性: name,id,salary,
提供必要的构造器和抽象方法;work()
2)对于Manager类来说,他既是员工,还具有奖金(bonus)的属性,
请使用继承的思想,设计CommonEmployee类和Manager类,要求实现work(),
提示"经理/普通员工名字工作中.…."
OOP继承+抽象类
"""
from abc import abstractmethod, ABC
# 父类-抽象类
class Employee(ABC):
def __init__(self, name, id, salary):
self.name = name
self.id = id
self.salary = salary
@abstractmethod
def work(self):
pass
# 子类CommonEmployee,Manager
class CommonEmployee(Employee):
def work(self):
print(f"普通员工{self.name}工作中.….")
class Manager(Employee):
def __init__(self, name, id, salary, bonus):
super().__init__(name, id, salary)
self.bonus = bonus
def work(self):
print(f"经理{self.name}工作中.….")
# 测试:
manager = Manager("king", "1-111", 10000, 100000)
manager.work()
commonemployee = CommonEmployee("tim","2-222",5000)
commonemployee.work()
P136 模板设计模式 2025/3/3
一、什么是设计模式
- 设计模式-简介:
- 设计模式是在大量的实践中总结和理论化之后优选的代码结构、编程风格、以及解决问题的思考方式
- 设计模式就像是经典的惯谱,不同的棋局,我们用不同的棋谱,免去我们自己再思考和摸索
二、模板设计模式
基本介绍:
- 抽象类体现的就是一种模板模式的设计,抽象类作为多个子类的通用模板,子类在抽象类的基础上进行扩展、改造,但子类总体上会保留抽象类的行为方式。
模板设计模式能解决的问题:
- 当功能内部一部分实现是确定,一部分实现是不确定的。这时可以把不确定的部分暴露出去,让子类去实现。
- 编写一个抽象父类,父类提供了多个子类的通用方法,并把一个或多个方法留给其子类实现,就是一种模板模式。
三、模板设计模式-最佳实践
开发需求:
- 有多个类,完成不同的任务job
- 要求统计得到各自完成任务的时间
- 请编程实现:
time.time()
:示意图:
- 优化-使用模板设计模式来解决:
- 设计一个抽象基类
(Template)
,能完成如下功能; - 编写方法
cal_time()
,可以计算某段代码的耗时时间 - 编写抽象方法
job()
- 编写一个子类,继承抽象类
Template
,并实现job
方法。 - 完成测试:
- 设计一个抽象基类
# @Author :zjc
# @File :30_模板设计模式.py
# @Time :2025/3/4 20:39
# 1)有多个类,完成不同的任务job
# 2)要求统计得到各自完成任务的时间
# 3)请编程实现使用模板设计模式
import time
from abc import abstractmethod, ABC
# 抽象类-模板类
class Template(ABC):
@abstractmethod
def job(self):
pass
# 统计任务执行时间
def cal_time(self):
# 得到开始的时间,豪秒数
start = time.time() * 1000
self.job()
# 得到结束的时间,秒数
end = time.time() * 1000
print("计算任务执行时间", (end - start))
class AA(Template):
def job(self):
num = 0
for i in range(1, 800001):
num += i
class BB(Template):
def job(self):
num = 1
for i in range(1, 900001):
num -= i
# 测试, 引出模板设计
if __name__ == '__main__':
aa = AA()
aa.cal_time()
bb = BB()
bb.cal_time()
P137 本章练习题 2025/3/4
一、练习题
sort()
函数:
# @Author :zjc
# @File :32_homework01.py
# @Time :2025/3/4 21:26
class Person:
def __init__(self, name, age, job):
self.name = name
self.age = age
self.job = job
def __str__(self):
return f"{self.name}--{self.age}--{self.job}"
p1 = Person("smith", 20, "java工程师")
p2 = Person("king", 18, "学生")
p3 = Person("HSP", 26, "老师")
my_list = [p1, p2, p3]
for p in my_list:
print(p)
# 有3个person对象,并按照age 从大到小进行排斑
"""
思路分析:
1. 解决方案:冒泡排序=>根据需求做了改进
2. 解决方案:直接使用列表的sort方法
"""
# 接收一个列表,里面的元素是Person对象
def bubble_sort(my_lsit: list[Person]):
"""
功能:对传入的列表排序-顺序从大到小(按照年龄)
:param my_lsit:传入的列表
:return:无
"""
# i变量来控制多少轮排序len
for i in range(0, len(my_lsit) - 1):
for j in range(0, len(my_lsit) - 1 - i): # [0,1,2]
# 如果前面的元素大于后面的元素就交换
# 如果是从小到大是:>;从大到小 <
if my_lsit[j].age < my_lsit[j + 1].age:
my_lsit[j], my_lsit[j + 1] = my_lsit[j + 1], my_lsit[j]
# 方法1.调用bubble
# bubble_sort(my_list)
# 方法2:直接使用列表sort()
"""
解读:
1. key=lambda ele:ele.age 表示我指定按照列表元素的age属性进行排序
将my_list的元素取出赋给ele,然后ele.age属性进行排序
2. reverse=True就是从大到小
"""
my_list.sort(key=lambda ele:ele.age,reverse=True)
print("排序后".center(32,"-"))
# 再次遍历:
for p in my_list:
print(p)
- 文件中有Grand , Father 和Son ,问:父类和子类中通过
self
和super()
都可以调用哪些属性和方法
# @Author :zjc
# @File :33_homework02.py
# @Time :2025/3/5 14:17
class Grand:
name = "AA"
__age = 100
def g1(self):
print("Grand-g1()")
class Father(Grand):
id = "001"
__score = None
def f1(self):
# super()可以访问哪些成员(属性和方法)?
# 填写?:super().name super().g1()
# self可以访问哪些成员?
# 填写?:self.name self.__score self.f1() self.name self.g1
print("Father-f1()")
class Son(Father):
name = "BB"
def g1(self):
print("Son-g1()")
def __show(self):
print("Son-__show()")
# super()可以访问哪些成员(属性和方法)?
# 填写:super().id super().f1 super().name super().g1
# self可以访问哪些成员?
# 填写self.name self.g1() self.__show self.id self.f1()
- 编写Doctor类,属性:name, age, job, gender, sal, 5个参数的构造器,重写
__eq__()
方法。并判断测试类中创建的两个对象是否相等(相等就是判断属性是否相同)
# @Author :zjc
# @File :34_homework03.py
# @Time :2025/3/5 15:03
# 编写Doctor类,属性:name, age, job, gender, sal,
# 5个参数的构造器,重写`__eq__()`方法。
# 并判断测试类中创建的两个对象是否相等(相等就是判断属性是否相同)
class Doctor:
def __init__(self, name, age, job, gender, sal):
self.name = name
self.age = age
self.gender = gender
self.sal = sal
self.job = job
# 重写__eq__
def __eq__(self, other):
# 如果other类型不合适Doctor,直接返回False
if not isinstance(other, Doctor):
return False
# 如果所有的属性都相同,则返回True
return (self.job == other.job
and self.name == other.name
and self.age == other.age
and self.gender == other.gender
and self.sal == other.sal)
# 测试:
doctor1 = Doctor("king", 30, "牙科医生", "男", 10000)
doctor2 = Doctor("king", 20, "牙科医生", "男", 10000)
print("doctor1 == doctor2", doctor2 == doctor1)
P138 本章小结 2025/3/5
一、小结
P139 出租系统需求和界面 2025/3/5
一、需求
项目需求说明:
- 实现基于文本界面的《房屋出租软件》
- 能够实现对房屋信息的添加、修改和删除,并能够打印房屋信息明细表
界面: