Python类与对象入门

学习目标

通过本集的学习,你将能够:

  • 理解面向对象编程的基本概念
  • 使用 class 关键字定义类
  • 掌握属性和方法的使用
  • 创建和使用对象
  • 理解 init 构造方法

1. 什么是面向对象?

面向对象编程(Object-Oriented Programming,简称OOP)是一种编程范式,将数据和操作数据的方法封装在一起。

1.1 面向对象 vs 面向过程

# 面向过程:关注"怎么做"
# 计算矩形面积
width = 5
height = 3
area = width * height
print(area)

# 面向对象:关注"是什么"
class Rectangle:
    def __init__(self, width, height):
        self.width = width
        self.height = height
    
    def area(self):
        return self.width * self.height

rect = Rectangle(5, 3)
print(rect.area())

1.2 类和对象的关系

类(Class) ──→ 蓝图/模板
    │
    ├─→ 属性(Attributes):数据
    └─→ 方法(Methods):操作

对象(Object) ──→ 类的实例
    │
    ├─→ 具体的个体
    └─→ 拥有类定义的所有属性和方法

类和对象的ASCII图:

        ┌─────────────────┐
        │   类:Car       │
        ├─────────────────┤
        │  属性:         │
        │    - color      │
        │    - speed      │
        ├─────────────────┤
        │  方法:         │
        │    - drive()    │
        │    - stop()     │
        └─────────────────┘
              │
              ├─→ 实例化
              │
        ┌─────┴─────┐
        ▼           ▼
   ┌─────────┐ ┌─────────┐
   │ 对象1   │ │ 对象2   │
   │ 红色    │ │ 蓝色    │
   │ 100km/h │ │ 80km/h  │
   └─────────┘ └─────────┘

2. 类的定义

2.1 基本类定义

# 最简单的类
class Person:
    pass  # 空类

# 创建对象
person1 = Person()
person2 = Person()

print(type(person1))  # 输出: <class '__main__.Person'>

2.2 带属性的类

class Person:
    # 类属性:所有实例共享
    species = "人类"
    
    # 实例属性:每个实例独有
    def __init__(self, name, age):
        self.name = name  # 实例属性
        self.age = age    # 实例属性

# 创建对象
person1 = Person("张三", 25)
person2 = Person("李四", 30)

# 访问属性
print(person1.name)   # 输出: 张三
print(person1.age)    # 输出: 25
print(person2.name)   # 输出: 李四

# 类属性
print(Person.species)      # 输出: 人类
print(person1.species)     # 输出: 人类
print(person2.species)     # 输出: 人类

2.3 init 构造方法

class Dog:
    def __init__(self, name, breed, age=1):
        """构造方法:创建对象时自动调用"""
        self.name = name
        self.breed = breed
        self.age = age
        print(f"一只叫{name}的{breed}出生了!")

# 创建对象
dog1 = Dog("旺财", "金毛", 3)
dog2 = Dog("来福", "柯基")  # 使用默认年龄

print(dog1.name)   # 输出: 旺财
print(dog2.age)    # 输出: 1

3. 属性与方法

3.1 实例方法

class Circle:
    def __init__(self, radius):
        self.radius = radius
    
    # 实例方法:第一个参数总是self
    def area(self):
        """计算圆的面积"""
        import math
        return math.pi * self.radius ** 2
    
    def circumference(self):
        """计算圆的周长"""
        import math
        return 2 * math.pi * self.radius
    
    def resize(self, new_radius):
        """修改半径"""
        self.radius = new_radius

# 使用
circle = Circle(5)
print(f"半径: {circle.radius}")
print(f"面积: {circle.area():.2f}")
print(f"周长: {circle.circumference():.2f}")

circle.resize(10)
print(f"\n修改后半径: {circle.radius}")
print(f"修改后面积: {circle.area():.2f}")

3.2 类方法和静态方法

class MathUtils:
    # 类属性
    version = "1.0"
    
    # 实例方法
    def instance_method(self):
        print("这是实例方法,可以访问self")
    
    # 类方法:用@classmethod装饰器,第一个参数是cls
    @classmethod
    def class_method(cls):
        print("这是类方法,可以访问cls")
        print(f"版本: {cls.version}")
    
    # 静态方法:用@staticmethod装饰器,没有特殊参数
    @staticmethod
    def static_method():
        print("这是静态方法,不需要self或cls")
    
    @staticmethod
    def add(a, b):
        return a + b

# 使用
MathUtils.class_method()
MathUtils.static_method()
print(MathUtils.add(3, 5))

utils = MathUtils()
utils.instance_method()

3.3 属性访问控制

class BankAccount:
    def __init__(self, balance=0):
        self.balance = balance  # 公开属性
    
    def deposit(self, amount):
        if amount > 0:
            self.balance += amount
            print(f"存款: {amount}")
    
    def withdraw(self, amount):
        if 0 < amount <= self.balance:
            self.balance -= amount
            print(f"取款: {amount}")
        else:
            print("余额不足")

# 使用
account = BankAccount(1000)
print(f"余额: {account.balance}")

account.deposit(500)
print(f"余额: {account.balance}")

account.withdraw(300)
print(f"余额: {account.balance}")

# 问题:可以直接修改balance
account.balance = 1000000  # 这不太好!
print(f"余额: {account.balance}")

# 使用下划线表示"受保护"的属性
class SafeBankAccount:
    def __init__(self, balance=0):
        self._balance = balance  # 单下划线:建议不要直接访问
    
    def get_balance(self):
        return self._balance
    
    def deposit(self, amount):
        if amount > 0:
            self._balance += amount
    
    def withdraw(self, amount):
        if 0 < amount <= self._balance:
            self._balance -= amount

safe_account = SafeBankAccount(1000)
print(f"余额: {safe_account.get_balance()}")
# 虽然可以访问 _balance,但不建议
# print(safe_account._balance)  # 不推荐!

4. 创建对象

4.1 实例化对象

class Student:
    def __init__(self, name, student_id, grades=None):
        self.name = name
        self.student_id = student_id
        self.grades = grades or []
    
    def add_grade(self, grade):
        self.grades.append(grade)
    
    def get_average(self):
        if not self.grades:
            return 0
        return sum(self.grades) / len(self.grades)

# 创建多个学生对象
student1 = Student("张三", "2024001", [85, 90, 78])
student2 = Student("李四", "2024002", [92, 88, 95])
student3 = Student("王五", "2024003")

student3.add_grade(76)
student3.add_grade(82)
student3.add_grade(80)

# 使用对象
students = [student1, student2, student3]
for student in students:
    avg = student.get_average()
    print(f"{student.name} ({student.student_id}): 平均分 {avg:.1f}")

4.2 对象的内存表示

每个对象在内存中都有独立的存储空间:

student1 ──→ ┌─────────────────┐
              │ name: "张三"     │
              │ student_id: ...  │
              │ grades: [...]    │
              └─────────────────┘

student2 ──→ ┌─────────────────┐
              │ name: "李四"     │
              │ student_id: ...  │
              │ grades: [...]    │
              └─────────────────┘

5. 实用案例

5.1 案例1:简单的购物车

# shopping_cart.py

class Product:
    """商品类"""
    def __init__(self, name, price, stock):
        self.name = name
        self.price = price
        self.stock = stock
    
    def __str__(self):
        return f"{self.name} - ¥{self.price} (库存: {self.stock})"

class ShoppingCart:
    """购物车类"""
    def __init__(self):
        self.items = {}  # {product: quantity}
    
    def add_item(self, product, quantity=1):
        """添加商品到购物车"""
        if product.stock < quantity:
            print(f"库存不足!{product.name}只剩{product.stock}件")
            return
        
        if product in self.items:
            self.items[product] += quantity
        else:
            self.items[product] = quantity
        
        product.stock -= quantity
        print(f"已添加 {quantity} 件 {product.name}")
    
    def remove_item(self, product, quantity=None):
        """从购物车移除商品"""
        if product not in self.items:
            print("购物车中没有此商品")
            return
        
        if quantity is None or quantity >= self.items[product]:
            product.stock += self.items[product]
            del self.items[product]
            print(f"已移除 {product.name}")
        else:
            self.items[product] -= quantity
            product.stock += quantity
            print(f"已移除 {quantity} 件 {product.name}")
    
    def get_total(self):
        """计算总价"""
        total = 0
        for product, quantity in self.items.items():
            total += product.price * quantity
        return total
    
    def show_cart(self):
        """显示购物车内容"""
        if not self.items:
            print("购物车为空")
            return
        
        print("购物车内容:")
        for product, quantity in self.items.items():
            subtotal = product.price * quantity
            print(f"  {product.name} x {quantity} = ¥{subtotal}")
        print(f"总价: ¥{self.get_total()}")

# 使用
apple = Product("苹果", 5.0, 100)
banana = Product("香蕉", 3.0, 50)
orange = Product("橙子", 4.0, 80)

cart = ShoppingCart()
cart.add_item(apple, 5)
cart.add_item(banana, 3)
cart.add_item(orange, 2)

print()
cart.show_cart()

print()
cart.remove_item(banana, 1)
cart.show_cart()

5.2 案例2:学生成绩管理系统

# grade_system.py

class Student:
    def __init__(self, name, student_id):
        self.name = name
        self.student_id = student_id
        self.courses = {}  # {course_name: grade}
    
    def add_course(self, course_name, grade):
        self.courses[course_name] = grade
    
    def get_gpa(self):
        if not self.courses:
            return 0
        return sum(self.courses.values()) / len(self.courses)
    
    def __str__(self):
        return f"{self.name} ({self.student_id})"

class GradeSystem:
    def __init__(self):
        self.students = {}  # {student_id: Student}
    
    def add_student(self, name, student_id):
        if student_id in self.students:
            print("学号已存在")
            return
        self.students[student_id] = Student(name, student_id)
        print(f"已添加学生: {name}")
    
    def add_grade(self, student_id, course_name, grade):
        if student_id not in self.students:
            print("学生不存在")
            return
        self.students[student_id].add_course(course_name, grade)
        print(f"已添加成绩: {course_name} - {grade}")
    
    def show_student(self, student_id):
        if student_id not in self.students:
            print("学生不存在")
            return
        student = self.students[student_id]
        print(f"\n{student}")
        print("课程成绩:")
        for course, grade in student.courses.items():
            print(f"  {course}: {grade}")
        print(f"GPA: {student.get_gpa():.2f}")
    
    def show_all_students(self):
        if not self.students:
            print("没有学生")
            return
        print("\n所有学生:")
        for student in self.students.values():
            print(f"  {student} - GPA: {student.get_gpa():.2f}")

# 使用
system = GradeSystem()
system.add_student("张三", "2024001")
system.add_student("李四", "2024002")

system.add_grade("2024001", "数学", 85)
system.add_grade("2024001", "英语", 90)
system.add_grade("2024001", "物理", 78)

system.add_grade("2024002", "数学", 92)
system.add_grade("2024002", "英语", 88)
system.add_grade("2024002", "物理", 95)

system.show_student("2024001")
system.show_all_students()

5.3 案例3:简单的银行账户

# bank_account.py

class BankAccount:
    """银行账户类"""
    
    # 类变量
    bank_name = "示例银行"
    total_accounts = 0
    
    def __init__(self, owner, initial_balance=0):
        self.owner = owner
        self._balance = initial_balance  # 受保护的余额
        self.account_number = self._generate_account_number()
        BankAccount.total_accounts += 1
        print(f"账户创建成功!{self.owner},账号: {self.account_number}")
    
    def _generate_account_number(self):
        """生成账号(内部方法)"""
        return f"ACC{BankAccount.total_accounts + 1:06d}"
    
    def deposit(self, amount):
        """存款"""
        if amount <= 0:
            print("存款金额必须大于0")
            return False
        self._balance += amount
        print(f"存款成功: ¥{amount},当前余额: ¥{self._balance}")
        return True
    
    def withdraw(self, amount):
        """取款"""
        if amount <= 0:
            print("取款金额必须大于0")
            return False
        if amount > self._balance:
            print(f"余额不足!当前余额: ¥{self._balance}")
            return False
        self._balance -= amount
        print(f"取款成功: ¥{amount},当前余额: �{self._balance}")
        return True
    
    def get_balance(self):
        """查询余额"""
        return self._balance
    
    def transfer(self, target_account, amount):
        """转账"""
        if self.withdraw(amount):
            target_account.deposit(amount)
            print(f"转账成功: ¥{amount} 从 {self.owner} 到 {target_account.owner}")
            return True
        return False
    
    def __str__(self):
        return f"[{self.account_number}] {self.owner} - 余额: ¥{self._balance}"

# 使用
print(f"欢迎使用 {BankAccount.bank_name}")
print()

account1 = BankAccount("张三", 1000)
account2 = BankAccount("李四", 500)

print()
print(account1)
print(account2)
print(f"总账户数: {BankAccount.total_accounts}")

print()
account1.deposit(500)
account2.withdraw(200)

print()
account1.transfer(account2, 300)

print()
print(account1)
print(account2)

6. 自测问题

  1. 类和对象的关系是什么?
  2. init 方法的作用是什么?
  3. 实例方法的第一个参数是什么?
  4. 类属性和实例属性的区别是什么?
  5. 什么是封装?

7. 下集预告

下一集我们将学习Python面向对象的进阶内容,包括继承、多态、封装等!

参考资料

« 上一篇 Python字典与集合 下一篇 » Python面向对象进阶