Python 面向对象与文件操作 —— 从类基础到图书馆实战项目

📅 学习周期:2025年5月16日 - 5月22日
🏷️ 标签:Python、面向对象、类、继承、文件操作、MySQL、实战项目
📝 本文整理自学习笔记,涵盖 Python OOP 核心知识点与图书馆管理系统实战


📑 目录


一、文件操作

1.1 基本文件复制

def file_copy(src, dest):
    # 打开源文件
    src_file = open(src, 'rb')
    # 读取源文件
    read_src_file = src_file.read()
    # 打开目标文件
    dest_file = open(dest, 'wb')
    # 写入目标文件
    dest_file.write(read_src_file)
    # 关闭文件
    src_file.close()
    dest_file.close()

1.2 高效文件复制(边读边写)

对于大文件,一次性读取会导致内存溢出。解决方案是分块读取,边读边写

def efficient_file_copy(src, dest):
    src_file = open(src, 'rb')
    dest_file = open(dest, 'wb')
    # 边读边写,每次读取 1024 字节
    while chunk := src_file.read(1024):
        dest_file.write(chunk)
    src_file.close()
    dest_file.close()

💡 这里用到了海象运算符 :=,下面详细介绍。


二、海象运算符(Walrus Operator)

Python 3.8 引入的海象运算符 :=,可以在表达式中边算边存,还能当值使用

普通赋值 vs 海象运算符

# 普通赋值:x = 10 → 把 10 存进 x(没有返回值)
# 海象运算:(x := 10) → 把 10 存进 x,同时返回 10

场景一:避免重复计算

# ❌ 不用海象:计算了两次 len(s)
s = 'hello python'
if len(s) > 5:
    print(f'长度是 {len(s)},超过5了')

# ✅ 用海象:只计算一次
s = 'hello python'
if (n := len(s)) > 5:
    print(f'长度是 {n},超过5了')

场景二:while 循环读取数据

# ❌ 不用海象:代码重复
data = input('请输入:')
while data != 'quit':
    print(f'你输入了:{data}')
    data = input('请输入:')  # 重复写了一遍 input

# ✅ 用海象:一行搞定
while (data := input('请输入:')) != 'quit':
    print(f'你输入了:{data}')

场景三:列表推导式中使用

import math
numbers = [1, 5, 12, 3, 20, 8, 15]

# ❌ 不用海象:先算再筛选,计算两次
results = [math.factorial(n) for n in numbers if math.factorial(n) > 100]

# ✅ 用海象:只算一次
results = [f for n in numbers if (f := math.factorial(n)) > 100]

三、类的定义与基本结构

class Person:
    home = 'earth'          # 类属性

    def __init__(self, name, age):  # 实例属性
        self.name = name
        self.age = age

    def eat(self):          # 实例方法
        print(self.name + " eats " + str(self.age))

    def drink(self):
        print(self.name + " is drinking " + str(self.age))

# 创建实例对象
zs = Person("张三", 20)
zs.eat()
zs.drink()
print(zs.home)  # 访问类属性

四、init 方法详解

__init__ 是 Python 类中非常重要的初始化方法:

⚠️ 在一些资料中将 __init__ 称为"构造函数",这种说法并不严谨

正确理解

  • 真正创建对象的是 __new__ 方法
  • __new__ 创建完对象后,会将对象交给 __init__
  • __init__ 主要完成初始化操作:给对象添加属性、给属性赋值
  • self 就是 __new__ 创建好的对象
  • 如果没有显式定义 __init__,系统底层会提供一个无参的 __init__
class Person:
    home = 'earth'

    def __init__(self, name, age):
        self.name = name
        self.age = age

    def eat(self):
        print(self.name + " eats " + str(self.age))

zs = Person("张三", 20)
zs.eat()
print(zs.home)

五、self 关键字底层原理

class Student():
    school = 'atguigu'

    def __init__(self, name, age):
        self.name = name
        self.age = age

    def study(self):
        print(f'年龄是{self.age}{self.name}在学习')

lwh = Student('lwh', 21)
print(lwh.name)
print(lwh.age)
lwh.study()

底层执行过程

一. 创建模块对象
   1. Student
   2. lwh

二. 创建类对象
   1. school(类属性)
   2. __init__
   3. study

三. 创建实例对象
   通过 __new__ 创建,将实例对象封装传给 __init__ 中的 self
   self → 实例对象的地址
   在 __init__ 中通过 self.name = name 给实例对象赋值

四. 调用实例方法
   self 接收实例对象的地址
   有了地址就可以访问实例对象的值

六、类属性与实例属性

6.1 访问与修改类属性

class Person:
    home = 'earth'

# 通过类名访问
print(Person.home)  # earth

lwh = Person()
print(lwh.home)     # earth

# 通过实例名修改(注意陷阱!)
lwh.home = '地球'
print(Person.home)  # earth(类属性没变!)
print(lwh.home)     # 地球(创建了实例属性)

# 通过类名修改
Person.home = '地球'
print(Person.home)  # 地球(类属性被修改)

⚠️ 关键区别

  • 通过类名修改 → 修改的是类属性本身
  • 通过实例名修改 → 在实例属性中创建同名属性,对类属性没有影响
  • 实例属性与类属性不能同名,否则会有歧义

6.2 实例属性的独立性

class Person:
    def __init__(self, name, age):
        self.name = name
        self.age = age

# 每个实例属性都占有不同的存储空间,互不影响
zs = Person('张三', 18)
ls = Person('李四', 20)

# 也可以在实例方法中定义实例属性
zs.eat()
print(zs.gender)  # 通过方法动态添加

# 也可以通过实例名添加
ls.gender = 'male'

七、三种方法:实例方法、类方法、静态方法

7.1 实例方法

class Person:
    home = 'earth'
    def __init__(self, name, age):
        self.name = name
        self.age = age

    # 实例方法:第一个参数为 self,代表实例本身
    def m1(self):
        print(Person.home)  # 访问类属性
        print(self.age)     # 访问实例属性
        self.m2()           # 调用其他实例方法

    def m2(self):
        print(self.home)

lwh = Person('张三', 18)
lwh.m1()

可以通过实例对象调用,也可以通过类名.方法名(self) 调用

7.2 类方法

class Person:
    home = 'earth'

    @classmethod
    def class_method(cls):
        print(cls.home)      # 可以访问类属性
        print(cls.__doc__)   # 可以访问文档字符串

# 使用场景:获取类成员但不想创建实例对象
Person.class_method()  # 通过类调用
p1 = Person()
p1.class_method()      # 通过实例调用

7.3 静态方法

class Person:
    home = 'earth'

    @staticmethod
    def static_method():
        print("static method")  # 不访问类/实例属性

Person.static_method()  # 通过类调用
p1 = Person()
p1.static_method()      # 通过实例调用

7.4 三种方法对比

方法类型 装饰器 第一个参数 能访问什么 调用方式
实例方法 self(实例) 实例属性、类属性 实例名.方法()
类方法 @classmethod cls(类) 类属性 类名.方法() 或 实例名.方法()
静态方法 @staticmethod 不访问内部信息 类名.方法() 或 实例名.方法()

八、面向对象综合实战:图书馆管理系统

8.1 Book 类(书籍)

class Book:
    library_name = 'Python图书馆'
    count = 0

    def __init__(self, book_name, author, price, stock):
        self.book_name = book_name
        self.author = author
        self.price = price
        self.stock = stock
        Book.count += 1

    def __str__(self):
        return f'《{self.book_name}》- 作者:{self.author}'

    __repr__ = __str__  # 让列表打印也用 __str__ 格式

    def __lt__(self, other):
        return self.price < other.price

    def sell_info(self):
        return {'书名': self.book_name, '作者': self.author,
                '价格': self.price, '库存': self.stock}

book1 = Book('西游记', '吴承恩', 45.0, 10)
book2 = Book('红楼梦', '曹雪芹', 55.0, 8)
book3 = Book('三国演义', '罗贯中', 50.0, 12)
print(book1)           # 《西游记》- 作者:吴承恩
print(book1 < book2)   # True(45 < 55)

8.2 EBook 类(电子书 - 继承)

class EBook(Book):
    def __init__(self, book_name, author, price, stock, file_size):
        super().__init__(book_name, author, price, stock)
        self.file_size = file_size

    def __str__(self):
        return f'《{self.book_name}》- 作者:{self.author} [电子书, 大小: {self.file_size}MB]'

    def download(self):
        print(f"正在下载《{self.book_name}》,文件大小:{self.file_size}MB")

ebook1 = EBook('Python入门', '小明', 29.9, 100, 15.5)
print(ebook1)   # 《Python入门》- 作者:小明 [电子书, 大小: 15.5MB]
ebook1.download()

8.3 Member 类(会员系统)

class Member:
    all_members = {}

    def __init__(self, name, level='普通'):
        self.name = name
        self.level = level
        self.borrowed_books = []  # 实例属性,每个对象独有
        if self.name not in Member.all_members:
            Member.all_members[self.name] = self.level

    def __str__(self):
        level = Member.all_members.get(self.name, self.level)
        return f"会员:{self.name}{level})"

    def __eq__(self, other):
        return self.name == other.name

    def borrow(self, book):
        self.borrowed_books.append(book.book_name)
        print(f"{self.name} 借阅了《{book.book_name}》")

    def return_book(self, book):
        if book.book_name in self.borrowed_books:
            self.borrowed_books.remove(book.book_name)
            print(f"{self.name} 归还了《{book.book_name}》")

    @classmethod
    def get_all_members(cls):
        return cls.all_members

    @classmethod
    def upgrade_all(cls):
        for name, level in cls.all_members.items():
            if level == '普通':
                cls.all_members[name] = 'VIP'
            elif level == 'VIP':
                cls.all_members[name] = 'SVIP'

m1 = Member('张三')
m1.borrow(book1)   # 张三 借阅了《西游记》
m1.borrow(book2)   # 张三 借阅了《红楼梦》
m1.return_book(book1)

8.4 Library 类(图书馆管理)

class Library:
    def __init__(self, name):
        self.name = name
        self.books = {}

    def add_book(self, book):
        if self.books.get(book.book_name) is None:
            self.books[book.book_name] = book
            print(f'添加成功:《{book.book_name}》')
        else:
            print(f'《{book.book_name}》已存在')

    def remove_book(self, book_name):
        if book_name in self.books:
            del self.books[book_name]
            print(f'已删除:《{book_name}》')

    def find_book(self, book_name):
        return self.books.get(book_name)

    def get_expensive_books(self, price_limit):
        return [b for b in self.books.values() if b.price >= price_limit]

    def lend(self, member, book_name):
        if book_name in self.books and self.books[book_name].stock > 0:
            self.books[book_name].stock -= 1
            print(f'{member.name} 借阅了《{book_name}》,剩余库存:{self.books[book_name].stock}')
        else:
            print(f'《{book_name}》库存不足')

    def receive(self, member, book_name):
        if book_name in self.books:
            self.books[book_name].stock += 1
            print(f'{member.name} 归还了《{book_name}》,当前库存:{self.books[book_name].stock}')

    def __str__(self):
        return f'{self.name},共{len(self.books)}本书'

library = Library('Python图书馆')
library.add_book(book1)
library.add_book(book2)
library.add_book(book3)
library.add_book(ebook1)
library.show_all()

九、进阶:Python + MySQL 图书馆系统

9.1 数据库表设计

CREATE DATABASE IF NOT EXISTS library_db DEFAULT CHARSET utf8mb4;
USE library_db;

-- 书籍表
CREATE TABLE IF NOT EXISTS books (
    id INT PRIMARY KEY AUTO_INCREMENT,
    book_name VARCHAR(50) NOT NULL UNIQUE,
    author VARCHAR(50) NOT NULL,
    price DECIMAL(10, 2) NOT NULL,
    stock INT NOT NULL DEFAULT 0,
    is_ebook TINYINT DEFAULT 0 COMMENT '0=纸质书 1=电子书',
    file_size DECIMAL(10, 2) DEFAULT NULL,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

-- 会员表
CREATE TABLE IF NOT EXISTS members (
    id INT PRIMARY KEY AUTO_INCREMENT,
    name VARCHAR(50) NOT NULL UNIQUE,
    level VARCHAR(20) DEFAULT '普通',
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

-- 借阅记录表
CREATE TABLE IF NOT EXISTS borrow_records (
    id INT PRIMARY KEY AUTO_INCREMENT,
    member_name VARCHAR(50) NOT NULL,
    book_name VARCHAR(50) NOT NULL,
    borrow_date TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    return_date TIMESTAMP NULL DEFAULT NULL,
    status VARCHAR(20) DEFAULT '借出'
);

9.2 数据库连接工具类

import pymysql

class DB:
    def __init__(self, host, port, user, password, database):
        self.host = host
        self.port = port
        self.user = user
        self.password = password
        self.database = database
        self.conn = None

    def connect(self):
        self.conn = pymysql.connect(
            host=self.host, port=self.port,
            user=self.user, password=self.password,
            database=self.database
        )

    def execute(self, sql, params=None):
        with self.conn.cursor() as cursor:
            cursor.execute(sql, params)
            self.conn.commit()

    def query(self, sql, params=None):
        with self.conn.cursor() as cursor:
            cursor.execute(sql, params)
            return cursor.fetchall()

    def close(self):
        if self.conn:
            self.conn.close()

    def __str__(self):
        return f'数据库连接:{self.user}@{self.host}:{self.port}/{self.database}'

9.3 关键提醒

# ❌ 危险!SQL 注入风险
db.execute(f"SELECT * FROM books WHERE name='{book_name}'")

# ✅ 安全!参数化查询
db.execute("SELECT * FROM books WHERE book_name=%s", (book_name,))

⚠️ 借还书时注意事务:UPDATE 库存 + INSERT 记录,两步要一起成功或一起失败。


十、常见易错点总结

10.1 类和对象

问题 错误写法 正确写法
super() 多传 self super().__init__(self, name) super().__init__(name)
列表打印显示地址 只定义 __str__ __repr__ = __str__
类属性 vs 实例属性混用 borrowed_books = [] 放类里 __init__
实例方法用 @classmethod @classmethod def lend(cls, ...) def lend(self, ...)
函数赋值加了括号 Person.drink = drink() Person.drink = drink
__len__ 返回字典 return self.books return len(self.books)

10.2 方法选择速查

需要访问 self(对象数据)  →  实例方法  def 方法名(self)
需要访问 cls(类的数据)   →  类方法    @classmethod def 方法名(cls)
什么都不需要访问           →  静态方法  @staticmethod def 方法名()

10.3 一句话总结

  1. super().__init__() 不传 self,参数要齐全
  2. __repr__ = __str__ 让列表打印好看
  3. 类属性共享,实例属性独有
  4. 实例方法用 self,类方法用 cls
  5. 函数赋值不加括号,调用才加括号
  6. 列表里存字符串(book_name),不存对象
  7. self.books.values() 取所有对象
  8. __len__ 返回数字,不是字典
  9. for 循环遍历完再 return,不要第一个就 return
  10. reduce 求平均:先求和再除

知识点覆盖总览

类和对象
├── __init__           初始化方法
├── __str__            面向用户的打印格式
├── __repr__           面向开发者的打印格式
├── __lt__             小于比较
├── __eq__             等于比较
├── __len__            len() 函数支持
├── 类属性             所有对象共享
├── 实例属性           每个对象独有
├── 实例方法           def 方法名(self)
├── 类方法 @classmethod
├── 静态方法 @staticmethod
├── 继承               class Child(Parent)
├── 方法重写           子类覆盖父类方法
└── super()            调用父类方法

文件操作
├── open() / read() / write() / close()
├── with 语句自动关闭
└── 海象运算符 := 边读边写

数据库
├── pymysql 连接
├── 参数化查询防注入
├── CRUD 操作
└── 事务管理

本文整理于 2026年5月20日,如需交流欢迎留言讨论!

更多推荐