Python | 第十三章 | 多态 | 魔术方法 | 静态方法 | 抽象类

发布于:2025-04-13 ⋅ 阅读:(21) ⋅ 点赞:(0)

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

image-20250221141119927

二、练习题

  1. 代码阅读题,看下面的代码,分析输出内容是什么?

image-20250221141220454

image-20250221141303936

# @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
  1. 对上面的代码做修改(将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

一、练习题

编程题:

  1. 定义员工类Employee,包含私有属性(姓名和月工资),以及计算年工资get_annual的方法
  2. 普通员工(Worker)和经理(Manager)继承员工类,经理类多了奖金bonus属性和管理manage方法,普通员工类多了work方法,普通员工和经理类要求根据需要重写get_annual方法
  3. 编写函数show_emp_annual(e:Employee),实现获取任何员工对象的年工资
  4. 编写函数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

一、基本介绍

  • 什么是魔术方法
  1. 在Python中,所有以双下划线包起来的方法,统称为Magic Method(魔术方法),它是一种的特殊方法,普通方法需要调用,而魔术方法不需要调用就可以自动执行。
  2. 魔术方法在类或对象的某些事件发生时会自动执行,让类具有神奇的"魔力"。如果希望根据自己的程序定制特殊功能的类,那么就需要对这些方法进行重写。
  3. Python中常用的运算符、for循环、以及类操作等都是运行在魔术方法之上的。
  • 常见的魔术方法

image-20250222172401045

二、常见魔术方法

  • 1、__str__基本介绍:
  1. 打印对象默认返回:类型名+对象内存地址【演示】,子类往往重写__str__,用于返回对象的属性信息
    main__.Person object at 0x0000019314BC7C90>
  2. 重写__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__基本介绍:
  1. == 是一个比较运算符:对象之间进行比较时,比较的是内存地址是否相等,即判断是不是同一个对象
  2. 重写__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

三、其他魔术方法

image-20250222192549868

  • 应用实例
    • 根据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)

二、静态方法

  • 基本介绍

    1. 参考文档:https://docs.python.org/zh-cn/3.12/library/functions.html#staticmethod

image-20250302211217646
3. @staticmethod将方法转换为静态方法
4. 静态方法不会接收隐式的第一个参数,要声明一个静态方法,语法:

class c:
    @staticmethod
    def f(arg1, arg2, argN): ...
  1. 静态方法既可以由类调用(如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("不知道是什么动物,不知道是什么叫声...")
  • 需求
    1. 当父类的某些方法,需要声明,但是又不确定如何实现时,怎么办?
    2. 不需要实例化父类对象,父类主要的是用于设计和制定规范,让其它类来继承并实现,怎么办?
    3. 解决方案->抽象类

二、抽象类介绍

  1. 默认情况下,Python不提供抽象类,Python附带一个模块,该模块为定义抽象基类提供了基础,该模块名称为abc
  2. 当我们需要抽象基类时,让类继承ABC(abc模块的ABC类),使用@abstractmethod声明抽象方法(@abstractmethod用于声明抽象方法的装饰器,在abc模块中),那么这个类就是抽象类
  3. 抽象类的价值更多作用是在于设计,是设计者设计好后,让子类继承并实现抽象类的抽象方法

三、快速入门

  • 参考文档: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()

image-20250303145811057

P135 抽象类细节和练习 2025/3/3

一、注意事项和细节

  1. 抽象类不能被实例化
  2. 抽象类需要继承ABC,并且需要至少一个抽象方法
# 抽象类需要继承ABC,并且需要至少一个抽象方法

from abc import ABC, abstractmethod


class AAA(ABC):
    name = "tim"

    # 如果有一个抽象方法是不能被实例化的
    @abstractmethod
    def f1(self):
        pass

#如果没有一个抽象方法,能实例化..
obj1 = AAA()
print( "ok")
  1. 抽象类中可以有普通方法
 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("~~~")
  1. 如果一个类继承了抽象类,则它必须实现抽象类的所有抽象方法,否则它仍然是一个抽象类
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("~~~")

二、练习题

image-20250303153524898

  • 代码
# @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()

image-20250303155438531

P136 模板设计模式 2025/3/3

一、什么是设计模式

  • 设计模式-简介
    1. 设计模式是在大量的实践中总结和理论化之后优选的代码结构、编程风格、以及解决问题的思考方式
    2. 设计模式就像是经典的惯谱,不同的棋局,我们用不同的棋谱,免去我们自己再思考和摸索

image-20250303175620500

二、模板设计模式

  • 基本介绍

    • 抽象类体现的就是一种模板模式的设计,抽象类作为多个子类的通用模板,子类在抽象类的基础上进行扩展、改造,但子类总体上会保留抽象类的行为方式。
  • 模板设计模式能解决的问题

    • 当功能内部一部分实现是确定,一部分实现是不确定的。这时可以把不确定的部分暴露出去,让子类去实现。
    • 编写一个抽象父类,父类提供了多个子类的通用方法,并把一个或多个方法留给其子类实现,就是一种模板模式。

三、模板设计模式-最佳实践

  • 开发需求

    • 有多个类,完成不同的任务job
    • 要求统计得到各自完成任务的时间
    • 请编程实现:
  • time.time()

    • image-20250304205142547
    • image-20250304205127317
  • 示意图

image-20250304210955666

  • 优化-使用模板设计模式来解决
    1. 设计一个抽象基类(Template),能完成如下功能;
    2. 编写方法cal_time(),可以计算某段代码的耗时时间
    3. 编写抽象方法job()
    4. 编写一个子类,继承抽象类Template,并实现job方法。
    5. 完成测试
# @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

一、练习题

image-20250304213028657

  • sort()函数:

image-20250304214708431

# @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)
  1. 文件中有Grand , Father 和Son ,问:父类和子类中通过selfsuper()都可以调用哪些属性和方法
# @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()
  1. 编写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)

image-20250305152036748

P138 本章小结 2025/3/5

一、小结

image-20250305152125508

P139 出租系统需求和界面 2025/3/5

一、需求

  • 项目需求说明

    • 实现基于文本界面的《房屋出租软件》
    • 能够实现对房屋信息的添加、修改和删除,并能够打印房屋信息明细表
  • 界面

image-20250305223124636

image-20250305223234284

image-20250305223252869

image-20250305223305866

image-20250305223523488

image-20250305223611009

image-20250305223652333

image-20250305223711010