当前位置: 代码网 > it编程>前端脚本>Python > 基于Python编写一个简单的图书管理系统

基于Python编写一个简单的图书管理系统

2026年07月27日 Python 我要评论
很多人学面向对象(oop),看了好几遍猫猫狗狗、汽车鸣笛的例子,轮到自己写项目时还是无从下手。今天我们拒绝源码赏析,直接开启“手把手带敲”模式。电脑前准备好你的代码编辑器,新建

很多人学面向对象(oop),看了好几遍猫猫狗狗、汽车鸣笛的例子,轮到自己写项目时还是无从下手。

今天我们拒绝源码赏析,直接开启“手把手带敲”模式。电脑前准备好你的代码编辑器,新建一个名为 library_system.py 的空文件。跟着文章每敲完一部分,我们就会用命令行运行测试一次。

等打通所有关卡,你会发现这个精密的系统已经自发在你手里诞生了!

准备关:搭建文件的地基

任何大楼都要先打地基。请在你的空 library_system.py 文件最顶部,敲下这几行代码。这包含了我们后面需要用到的工具库,以及一个控制借书权限的全局变量。

from abc import abc, abstractmethod
import json

# 定义一个全局变量,表示会员的借阅上限
base_borrow_limit = 3

这里的技术点科普:

  • from abc import ...abc 是 abstract base classes(抽象基类)的缩写。它是 python 用来定规矩、立契约的工具。我们用它来确保后面的会员系统不管怎么变,都必须遵守相同的行业标准。
  • 全局变量:我们把 base_borrow_limit = 3 放在最顶层,意思是这是全系统公用的初始标准。以后就算图书馆想把上限改成 5 本,我们也只需要改这一行数字,不用去代码堆里到处找,这叫便于维护。

第一关:构建图书类 —— 搞懂【封装】

有了地基,我们来写第一个类 book。我们要把书的信息锁在类内部,不让外面的人随随便便把库存数量改错(比如不小心改出负数)。

敲入图书类代码

请紧接着在刚才的基础变量下方,敲入 book 类的实现:

class book:
    def __init__(self, book_id, title, author, total_quantity, available_quantity):
        # 初始化书籍信息
        self.book_id = book_id
        self.title = title
        self.author = author
        self.total_quantity = total_quantity
        # 🔒 封装的核心:定义一个私有变量,表示书籍的余量
        self.__available_quantity = available_quantity

    # 定义一个获取书籍余量的方法
    def get_available_quantity(self):
        return self.__available_quantity

    # 定义一个设置书籍余量的方法
    def set_available_quantity(self, available_quantity):
        self.__available_quantity = available_quantity

    # 格式化输出书籍信息
    def __str__(self):
        return f"编号:{self.book_id},书名:{self.title},作者:{self.author},总数量:{self.total_quantity},余量:{self.get_available_quantity()}"

代码大白话拆解与科普:

  • __init__ 构造函数:每次我们要创建一本真实的书(专业术语叫实例化)时,python 会自动调用这个方法,把书名、作者等数据塞进这个对象的口袋里。
  • 私有变量 self.__available_quantity:注意看变量名前面的双下划线 __!这是 python 的安全锁。一旦加了它,外面的代码就无法直接通过 book.__available_quantity = -5 这种恶作剧的方式去改库存了。
  • getter/setter 机制(get_... / set_...):既然库存被锁死了,外面怎么看库存、改库存呢?我们专门开了两个公开的“安全通道”方法。外部必须客客气气地调用 set_available_quantity() 才能改库存。实际开发中,我们可以在 set 方法内部加一句校验:if available_quantity < 0: 拦截报错,数据安全感直接拉满!
  • 魔术方法 __str__:这是 python 内置的特殊方法。它的作用是:当别人在外面直接执行 print(book) 时,python 不会打印出一串看不懂的内存地址,而是会自动触发这个方法,打印出你精心拼装的漂亮字符串。

见证成就感时刻(第一次命令行测试)

现在,我们在刚写好的 book 类最下方,临时敲入以下测试代码:

if __name__ == "__main__":
    book = book("b001", "python编程:从入门到实践", "eric matthes", 10, 10)
    print(book)
    
    book.set_available_quantity(9)
    print(f"安全通道修改后的余量:{book.get_available_quantity()}")

打开你的终端(windows 用 cmdpowershell,mac/linux 用 terminal),切换到你保存文件的目录下,敲入以下命令并回车:

python library_system.py

运行结果:

编号:b001,书名:python编程:从入门到实践...余量:10
安全通道修改后的余量:9

这就是面向对象的第一个魔法:【封装】。把数据锁在家里,通过公开的方法去访问。

注意:测试成功后,请把刚才临时加的最底下 5 行测试块删掉,我们要继续往上盖楼了!

第二关:构建会员体系 —— 搞懂【继承与抽象】

接下来做会员。我们系统里有两种人:普通会员最多借 3 本;vip 会员由于身份尊贵,借书上限会随着等级增加。

为了避免重复写两遍借还书的代码,我们先写一个统一的“老爸类”定下规范契约。

敲入会员抽象类

请在 book 类的正下方,紧接着敲入父类 member 的代码:

class member(abc):
    def __init__(self, card_no, password, name):
        # 初始化成员信息
        self.card_no = card_no
        self.password = password
        self.name = name
        # 初始化借阅列表
        self.borrowed_books = []

    @abstractmethod
    # 定义一个抽象方法,子类必须实现
    def get_max_book(self):
        pass

    def borrow_book(self, book: book):
        # 如果借阅的书籍数量小于设定值,则将书籍添加到借阅列表中并返回true,否则返回false
        if len(self.borrowed_books) < self.get_max_book():
            self.borrowed_books.append(book)
            print(f"{self.name}借阅了{book.title}")
            return true
        else:
            print("你借阅的书籍数量已达到上限")
            return false

    # 定义一个返回书籍的方法
    def return_book(self, book: book):
        # 如果书籍在借阅列表中,则将其移除并返回true,否则返回false
        if book in self.borrowed_books:
            self.borrowed_books.remove(book)
            return true
        else:
            print("你并未借阅此书")
            return false

    def get_borrowed_books(self):
        # 如果会员没有借阅任何书籍,则输出提示信息
        if len(self.borrowed_books) == 0:
            print("你还没有借阅任何书籍。")
        else:
            print(f"{self.name}借阅的书籍:")
            # 遍历会员的借阅记录,输出书籍信息
            for book in self.borrowed_books:
                print(f"书籍编号:{book.book_id},书名:{book.title},作者:{book.author}")

代码大白话拆解与科普:

  • member(abc) 抽象基类:由于括号里写了 abc,说明 member 变成了一个“概念规范类”。它的目的是作为所有会员的亲生老爸,在系统里你不能直接去实例化一个模糊的 member(比如你不能执行 m = member(...),python 会直接报错拦截)。
  • 装饰器 @abstractmethod:这标志着 get_max_book() 是一个抽象方法。老爸对所有儿子说:“我不知道你们各自的借书上限是怎么算的,所以我把这个方法空着(pass)。但我命令你们,凡是继承我的子类,必须把这个方法的具体算账逻辑给我补齐了,不写就让你程序报错跑不起来!”
  • 灵魂多态判定 self.get_max_book():仔细看 borrow_book 里的那句 if len(...) < self.get_max_book():。这一句是全人类面向对象编程的精髓! 父类在写核心借书业务时,根本不用管未来会有多少种会员。它只需要闭着眼睛调用 self.get_max_book()。当普通会员借书时,这一句自动变成检查固定限制;当 vip 借书时,这一句自动变成按等级计算限制。这就是多态的雏形——父类搭好核心框架,子类决定具体细节。

增量派生“普通会员”与“vip 会员”

有了契约老爸,我们现在给它派生出两个具体的会员。请在 member 类的正下方,紧接着敲下:

class normalmember(member):
    def __init__(self, card_no, password, name):
        # 继承父类的构造函数
        super().__init__(card_no, password, name)

    # 实现抽象方法,返回普通会员的借阅上限
    def get_max_book(self):
        return base_borrow_limit


class vipmember(member):
    def __init__(self, card_no, password, name, level):
        # 继承父类的构造函数
        super().__init__(card_no, password, name)
        # 初始化会员等级
        self.level = level

    # 实现抽象方法,返回会员的借阅上限
    def get_max_book(self):
        return base_borrow_limit + self.level

代码大白话拆解与科普:

  • class normalmember(member) 继承:括号里写了 member,代表它认领了父类。子类不需要再辛辛苦苦去写一遍名字、卡号、借书还书的方法。老爸的所有本事,它一句话就全自动学会了。这在开发里叫代码复用,能帮程序员省下大量抄代码的时间。
  • super().__init__(...):这一句的意思是“呼叫老爸的构造函数”。当创建普通会员或 vip 时,把卡号、密码、姓名直接扔给父类的构造函数去初始化,子类省时省力。
  • 属性扩展(self.level = level):vip 毕竟是 vip,他有普通人没有的特权。所以 vipmember 除了继承老爸的基础底子外,还自己增量扩展了一个独有的属性 level

见证成就感时刻(第二次命令行测试)

老规矩,我们在文件最底部敲入以下临时测试块,看看借书拦截功能起效了没有:

if __name__ == "__main__":
    book_test = book("b001", "python编程", "eric", 10, 10)
    normal_man = normalmember("n10001", "123456", "张三")
    vip_man = vipmember("v10002", "456789", "李四", level=1) # 上限 3+1=4本

    print("--- 测试张三(普通限制3本) ---")
    for _ in range(4): normal_man.borrow_book(book_test)

    print("\n--- 测试李四(vip1限制4本) ---")
    for _ in range(4): vip_man.borrow_book(book_test)

保存文件,打开终端,再次敲入命令行并回车:

python library_system.py

观察控制台输出:

--- 测试张三 ---
张三借阅了python编程 (成功3次)
你借阅的书籍数量已达到上限 (第4次被老爸类完美拦截!)

--- 测试李四 ---
李四借阅了python编程 (李四成功借到了4次!)

这就是面向对象的第二和第三个魔法:【继承】与【多态】。子类继承了老爸的代码,同时父类的同一套规则(borrow_book)在面对不同对象时,展现出了不同的逻辑形态。

测试完后,再次把最底部的测试块删掉,我们要盖最后一层——大管家类!

第三关:搭建系统的“大管家” —— 统筹联动与真实数据存储

书和人都准备好了,现在我们需要最后一个类 library,作为大管家把所有东西装进来,并实现真正的文件交互。

准备真实的 json 数据文件

为了让接下来的代码不报错,请在你的代码文件同级目录下,创建一个名叫 json 的文件夹,并在里面新建两个文本文件:

新建 json/members.json 并写入以下真实的会员数据:

[  { "card_no": "n10001", "password": "123456", "name": "张三" },  { "card_no": "v10002", "password": "456789", "name": "李外", "level": 1 }]

新建 json/books.json 并写入以下真实的图书数据:

[  { "book_id": "b001", "title": "python编程:从入门到实践", "author": "eric matthes", "total_quantity": 10, "available_quantity": 10 },  { "book_id": "b002", "title": "算法导论", "author": "thomas h. cormen", "total_quantity": 10, "available_quantity": 10 },  { "book_id": "b003", "title": "计算机网络:自顶向下方法", "author": "james f. kurose", "total_quantity": 10, "available_quantity": 2 }]

敲入大管家的初始化与数据加载

请在刚才两个会员子类的正下方,紧接着敲入大管家 library 类的代码:

class library:
    def __init__(self):
        # 初始化会员和书籍列表
        self.members = {}
        self.books = {}
        self.current_member: member | none = none

        self.load_members()
        self.load_books()

    def load_members(self):
        # 从json文件中加载会员和书籍信息
        with open("json/members.json", "r", encoding="utf-8") as f:
            members = json.load(f)
            for member in members:
                if member["card_no"].startswith("v"):
                    # 根据会员卡号的前缀判断会员类型,并创建相应的会员对象
                    self.members[member["card_no"]] = vipmember(
                        member["card_no"],
                        member["password"],
                        member["name"],
                        member["level"],
                    )
                elif member["card_no"].startswith("n"):
                    # 如果会员卡号以n开头,则创建普通会员对象
                    self.members[member["card_no"]] = normalmember(
                        member["card_no"], member["password"], member["name"]
                    )

    def load_books(self):
        # 从json文件中加载书籍信息
        with open("json/books.json", "r", encoding="utf-8") as f:
            books = json.load(f)
            # 将书籍信息转换为book对象,并添加到书籍列表中
            for book in books:
                self.books[book["book_id"]] = book(
                    book["book_id"],
                    book["title"],
                    book["author"],
                    book["total_quantity"],
                    book["available_quantity"],
                )

    def show_all_books(self):
        print("【所有书籍】")
        for book in self.books.values():
            print(book)

 代码大白话拆解与科普:

  • self.current_member: member | none 类型注解:这行代表当前正在登录系统的会员。后面的 member | none 是现代 python 的标准写法,意思是:这个变量要么是空的(none),要么就必须是一个符合 member 规范的会员对象。这能让你的代码极具工程严谨性。
  • 简单工厂模式思想(card_no.startswith):看 load_members 内部!大管家在读取死的 json 数据时,通过判断卡号的前缀('v' 还是 'n'),在程序运行时动态决定是在内存里实例化一个 vipmember 还是 normalmember。数据是死的,但在加载的一瞬间,它们全都被赋予了不同的生命和特权!
  • 对封装的无缝调用:在 show_all_books 里,大管家遍历并直接 print(book)。由于我们在第一关写好了 __str__ 魔术方法,这里大管家闭着眼睛就能打印出格式规整的图书列表。

增量敲入核心业务逻辑(登录/借书/还书)

不要另起新行,请紧接着在刚才 show_all_books 的屁股后面,把借书和还书的协同功能补全:

    def login(self):
        print("【登录】")
        while true:
            card_no = input("请输入你的会员卡号:")
            password = input("请输入你的密码:")

            # 验证会员卡号和密码
            if card_no not in self.members:
                print("会员卡号不存在,请重新输入。")
                continue

            if self.members[card_no].password != password:
                print("密码错误,请重新输入。")
                continue

            # 当前会员信息
            self.current_member = self.members[card_no]
            print(f"\n欢迎你,{self.current_member.name}!")
            return true

    # 借阅书籍
    def borrow_book(self):
        book_id = input("请输入书籍编号:")

        # 验证书籍是否存在
        if book_id not in self.books:
            print("书籍不存在,请重新输入。")
            return false

        available_quantity = self.books[book_id].get_available_quantity()
        # 验证书籍是否可借
        if available_quantity == 0:
            print("书籍已被借完,请重新输入。")
            return false

        # 🤝 【高内聚低耦合的多态协同】
        # 借阅成功,调用对应会员类定义的借阅数据方法,并减少书籍的余量
        if self.current_member.borrow_book(self.books[book_id]):
            self.books[book_id].set_available_quantity(available_quantity - 1)
            return true

    # 归还书籍
    def return_book(self):
        book_id = input("请输入书籍编号:")

        # 验证书籍是否存在
        if not self.books.get(book_id):
            print("你并未借阅此书!")
            return false

        available_quantity = self.books[book_id].get_available_quantity()
        # 归还成功,调用对应会员类定义的归还数据方法,并增加书籍的余量
        if self.current_member.return_book(self.books[book_id]):
            self.books[book_id].set_available_quantity(available_quantity + 1)
            print(f"书籍编号:{book_id},书名:{self.books[book_id].title},作者:{self.books[book_id].author}归还成功!")
            return true

代码大白话拆解与科普:

跨对象协同与解耦(全书最核心亮点):注意看 borrow_book 里的这句:if self.current_member.borrow_book(...)

大管家类自己并没有去写复杂的“这个会员到底能不能借这本书”的逻辑。大管家非常聪明,它直接把书籍对象作为参数,甩给了当前登录的会员对象:“你看看你自己的额度,你觉得能借吗?”

这就叫各司其职(低耦合)。会员自己核对完毕说可以(返回 true),大管家才在外面调用图书类封装好的 set_available_quantity 把库存减一。大管家、会员、图书三个完全独立的类,在这一瞬间完成了精妙的配合!

增量敲入系统控制台菜单

紧接着在刚才 return_book 的下方,敲入整个项目的交互菜单。我们使用了 python 3.10+ 最整洁的 match-case 语法:

    # 开始运行
    def run(self):
        if self.login():
            print("""
                  
                    # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # 
                    # 1. 借阅书籍  2. 归还书籍  3.查看所有书籍  4.查看借阅记录  5.退出系统  #
                    # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
                  
                """)

            while true:
                choice = input("请输入你的 choice:")

                match choice:
                    # 借阅书籍
                    case "1":
                        self.show_all_books()
                        self.borrow_book()

                    # 归还书籍
                    case "2":
                        self.current_member.get_borrowed_books()
                        self.return_book()

                    # 查看所有书籍
                    case "3":
                        self.show_all_books()

                    # 查看借阅记录
                    case "4":
                        self.current_member.get_borrowed_books()

                    # 退出系统
                    case "5":
                        print("退出系统成功!")
                        exit()

                    case _:
                        print("输入错误,请重新输入。")
                        continue

代码大白话拆解与科普:

  • match-case 语法:这是 python 3.10 引入的现代控制流语法(类似于其他语言的 switch-case)。相比于以前写满屏幕的 if-elif-elif-else,它结构更清晰、可读性极高。最后的 case _: 代表通配符,用来拦截所有不在 1~5 范围内的错误输入。
  • 多态的终极展现:在选项 4 case "4": self.current_member.get_borrowed_books() 中,无论当前登录的人是普通卡张三还是 vip 卡李四,大管家都只负责调用这一行相同的命令。python 会在运行期间自动找到它们各自子类的具体方法去执行。

终点站:全线通电,启动系统!

现在,你的整个脚本文件已经一气呵成、全部无缝连成一体了。请在整份文件的最底部,敲下这最后的四行启动入口:

if __name__ == "__main__":
    # 创建图书馆对象
    library = library()
    library.run()

最后的完整命令行大测试

保存你的文件。打开终端,再次敲入终极运行命令:

python library_system.py

在终端里跟着提示输入:

  1. 会员卡号输入 n10001,密码输入 123456 登录张三。
  2. 输入选择 1 借阅书籍,然后输入书籍编号 b001
  3. 借阅成功后,再输入选择 3 查看所有书籍。

你会神奇地在命令行控制台里看到:b001 这本书的 余量 真的由 10 本动态变成了 9 本!这就证明你的系统已经大功告成、完美闭环。

总结

跟着这篇文章从头敲到尾,你不仅仅是在本地拥有了一个能进行文件交互的图书管理 demo,更重要的是你搞懂了面向对象的终极意义:

  1. 封装:book 锁住库存数量,提供 getter/setter,数据安全得到保障。
  2. 继承:各种会员利用 super() 复用父类逻辑,彻底消灭重复代码。
  3. 多态:大管家闭着眼睛下达统一指令,python 会自动根据对象实际的类型去执行具体的逻辑。

面向对象编程从来不是条条框框,它是当你面对真实复杂的业务数据时,帮你梳理逻辑、让你少写重复代码、少加班的终极武器。

以上就是基于python编写一个简单的图书管理系统的详细内容,更多关于python图书管理系统的资料请关注代码网其它相关文章!

(0)

相关文章:

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论

验证码:
Copyright © 2017-2026  代码网 保留所有权利. 粤ICP备2024248653号
站长QQ:2386932994 | 联系邮箱:2386932994@qq.com