Python编程基础:类(class)和构造函数

系统性地讲解Python类(class)和构造函数的相关知识。这是Python面向对象编程的核心内容。

1. 基础类定义

最简单的类

PYTHON 复制代码
class MyClass:
    """这是一个简单的类"""
    pass


# 创建实例
obj = MyClass()
print(obj)  # <__main__.MyClass object at 0x...>

2. 构造函数详解

构造函数是创建对象时自动调用的方法,在Python中是 __init__ 方法。

2.1 默认构造函数

PYTHON 复制代码
class Person:
    def __init__(self):
        """默认构造函数,没有额外参数"""
        self.name = "无名氏"
        self.age = 0
        print("默认构造函数被调用")

# 使用
p1 = Person()
print(p1.name)  # 无名氏
print(p1.age)   # 0

2.2 带参构造函数

所有参数都是必须的

PYTHON 复制代码
class Person:
    def __init__(self, name, age):
        """带参数的构造函数,所有参数都是必须的"""
        self.name = name
        self.age = age
        print("带参构造函数被调用")

# 使用
p2 = Person("张三", 25)
print(p2.name, p2.age)  # 张三 25


# 错误示例:缺少参数会报错
# p3 = Person()  # TypeError
# p4 = Person("李四")  # TypeError

2.3 混合参数构造函数(可选参数)

使用默认值创建可选参数

PYTHON 复制代码
class Person:
    def __init__(self, name, age=18, city="北京"):
        """
        混合参数的构造函数
        name: 必须参数
        age: 可选参数,默认18
        city: 可选参数,默认"北京"
        """
        self.name = name
        self.age = age
        self.city = city
        print("混合参数构造函数被调用")


# 使用方式1:提供所有参数
p1 = Person("张三", 25, "上海")
print(p1.name, p1.age, p1.city)


# 使用方式2:只提供必须参数
p2 = Person("李四")
print(p2.name, p2.age, p2.city)  # 李四 18 北京


# 使用方式3:提供部分可选参数
p3 = Person("王五", 30)
print(p3.name, p3.age, p3.city)  # 王五 30 北京


# 使用方式4:使用关键字参数
p4 = Person(name="赵六", city="广州")
print(p4.name, p4.age, p4.city)  # 赵六 18 广州

更灵活的参数组合

PYTHON 复制代码
class Employee:
    def __init__(self, name, salary, department="技术部", 
                 position="工程师", email=None):
        """
        name: 必须参数
        salary: 必须参数
        department: 可选参数,默认"技术部"
        position: 可选参数,默认"工程师"
        email: 可选参数,默认None
        """
        self.name = name
        self.salary = salary
        self.department = department
        self.position = position
        self.email = email if email else f"{name}@company.com"
    
    def display_info(self):
        info = f"""
        === 员工信息 ===
        姓名: {self.name}
        部门: {self.department}
        职位: {self.position}
        邮箱: {self.email}
        薪资: {self.salary}
        """
        print(info)


# 使用
emp1 = Employee("张三", 8000)
emp1.display_info()


emp2 = Employee("李四", 10000, "市场部", "经理", "lisi@company.com")
emp2.display_info()

3. 完整示例:学生管理系统

PYTHON 复制代码
class Student:
    # 类属性:所有实例共享
    school = "XX大学"
    total_students = 0
    
    def __init__(self, student_id, name, age, major=None, 
                 grade_points=0.0, is_active=True):
        """
        student_id: 学号(必须)
        name: 姓名(必须)
        age: 年龄(必须)
        major: 专业(可选,默认None)
        grade_points: 绩点(可选,默认0.0)
        is_active: 是否在读(可选,默认True)
        """
        self.student_id = student_id
        self.name = name
        self.age = age
        self.major = major if major else "未定专业"
        self.grade_points = grade_points
        self.is_active = is_active
        
        # 每个实例创建时增加总学生数
        Student.total_students += 1
    
    def update_grade(self, new_grade):
        """更新绩点"""
        self.grade_points = new_grade
        print(f"{self.name}的绩点已更新为: {new_grade}")
    
    def change_major(self, new_major):
        """更换专业"""
        old_major = self.major
        self.major = new_major
        print(f"{self.name}的专业已从{old_major}更换为{new_major}")
    
    def get_student_status(self):
        """获取学生状态"""
        status = "在读" if self.is_active else "已毕业/休学"
        return f"学号:{self.student_id} 姓名:{self.name} 专业:{self.major} 状态:{status}"
    
    @classmethod
    def get_total_students(cls):
        """类方法:获取学生总数"""
        return f"学校总学生数: {cls.total_students}"
    
    @staticmethod
    def calculate_grade_level(grade_points):
        """静态方法:根据绩点判断等级"""
        if grade_points >= 4.0:
            return "优秀"
        elif grade_points >= 3.0:
            return "良好"
        elif grade_points >= 2.0:
            return "及格"
        else:
            return "不及格"


# 使用示例
# 创建学生实例
stu1 = Student("2023001", "小明", 20, "计算机科学", 3.8)
stu2 = Student("2023002", "小红", 21, grade_points=3.2)
stu3 = Student("2023003", "小刚", 22, "物理学")  # 使用默认绩点0.0


# 打印学生信息
print(stu1.get_student_status())
print(stu2.get_student_status())
print(stu3.get_student_status())


# 调用实例方法
stu1.update_grade(4.0)
stu2.change_major("人工智能")


# 调用类方法
print(Student.get_total_students())


# 调用静态方法
print(f"小明的等级: {Student.calculate_grade_level(stu1.grade_points)}")

4. 进阶:更复杂的构造函数

4.1 使用 *args 接受任意数量的位置参数

PYTHON 复制代码
class Product:
    def __init__(self, name, price, *tags):
        """
        name: 商品名称
        price: 价格
        *tags: 可变数量的标签
        """
        self.name = name
        self.price = price
        self.tags = list(tags)
    
    def add_tag(self, tag):
        self.tags.append(tag)
    
    def show_tags(self):
        return f"{self.name}的标签: {', '.join(self.tags)}"


p1 = Product("手机", 2999, "电子产品", "通讯", "便携")
print(p1.show_tags())  # 手机的标签: 电子产品, 通讯, 便携


p2 = Product("笔记本", 4999, "办公", "学习")
print(p2.show_tags())  # 笔记本的标签: 办公, 学习

4.2 使用 **kwargs 接受任意数量的关键字参数

PYTHON 复制代码
class Car:
    def __init__(self, brand, model, **specifications):
        """
        brand: 品牌
        model: 型号
        **specifications: 其他技术参数
        """
        self.brand = brand
        self.model = model
        self.specifications = specifications
    
    def get_full_info(self):
        info = f"{self.brand} {self.model}\n规格参数:"
        for key, value in self.specifications.items():
            info += f"\n  {key}: {value}"
        return info


car1 = Car("特斯拉", "Model 3", color="红色", range=500, autopilot=True)
print(car1.get_full_info())


car2 = Car("比亚迪", "汉", color="黑色", battery_type="刀片电池", 
           acceleration=3.9, range=605)
print(car2.get_full_info())

4.3 混合使用默认参数、*args、**kwargs

python 复制代码
<PYTHON>
class Config:
    def __init__(self, name, default_value=None, *args, **kwargs):
        """
        复杂的参数配置类
        """
        self.name = name
        self.default_value = default_value
        self.args = args
        self.options = kwargs
    
    def display_config(self):
        print(f"配置名称: {self.name}")
        print(f"默认值: {self.default_value}")
        print(f"额外参数: {self.args}")
        print(f"选项: {self.options}")


# 使用
c1 = Config("数据库配置", "localhost:3306", "utf8", "pool=10", 
            timeout=30, max_connections=100)
c1.display_config()

5. 最佳实践建议

  1. 参数顺序:将必须参数放在前面,可选参数放在后面
  2. 默认值设置 :使用None作为默认值,然后在构造函数内赋值
  3. 类型提示:使用类型提示提高代码可读性
  4. 文档字符串:为构造函数和方法添加文档字符串
  5. 参数验证:在构造函数中进行参数验证
PYTHON 复制代码
from typing import Optional, List, Dict


class User:
    def __init__(self, 
                 username: str, 
                 email: str, 
                 age: int = 18,
                 roles: Optional[List[str]] = None,
                 preferences: Optional[Dict] = None):
        """
        用户类
        
        Args:
            username: 用户名(必须)
            email: 邮箱(必须)
            age: 年龄(可选,默认18)
            roles: 角色列表(可选)
            preferences: 偏好设置(可选)
        """
        # 参数验证
        if not username:
            raise ValueError("用户名不能为空")
        
        # 'email' 简单验证
        if '@' not in email:
            raise ValueError("邮箱格式不正确")
        
        self.username = username
        self.email = email
        self.age = age
        
        # 处理可变默认参数
        self.roles = roles if roles is not None else []
        self.preferences = preferences if preferences is not None else {}
    
    def __str__(self):
        return f"User(username={self.username}, email={self.email}, age={self.age})"


# 使用
user1 = User("john_doe", "john@example.com")
user2 = User("jane_doe", "jane@example.com", 25, ["admin", "editor"])

6. 使用dataclass简化类定义(Python 3.7+)

PYTHON 复制代码
from dataclasses import dataclass, field
from typing import List


@dataclass
class Product:
    name: str
    price: float
    tags: List[str] = field(default_factory=list)
    stock: int = 0
    
    def is_available(self):
        return self.stock > 0


# 自动生成 __init__, __repr__ 等方法
p1 = Product("手机", 2999.0, ["电子", "通讯"], 10)
print(p1)  # Product(name='手机', price=2999.0, tags=['电子', '通讯'], stock=10)
print(p1.is_available())  # True

总结

  • 构造函数 :使用 __init__ 方法定义
  • 必须参数:放在参数列表最前面,调用时必须提供
  • 可选参数 :使用 =默认值 的形式定义
  • 灵活参数 :使用 *args**kwargs
  • 最佳实践:添加类型提示、参数验证和文档字符串

什么是 typing 库?

想象一下你有一个装零食的盒子:

  • 没有类型注解:你只知道盒子里有东西,但不知道是什么
  • 有类型注解:盒子上贴着标签:"糖果"、"饼干"、"巧克力"

typing 就是给代码"贴标签"的工具!

最简单的理解方式

1. List - "列表标签"

告诉别人这个列表里装的是什么

PYTHON 复制代码
from typing import List


# 没有标签(不知道盒子里是什么)
names = ["小明", "小红", "小刚"]


# 有标签(明确告诉大家是"字符串列表")
names: List[str] = ["小明", "小红", "小刚"]
# ↑ 就像在盒子上写:"装的是名字(字符串)"

2. Dict - "字典标签"

告诉别人字典里的"钥匙"和"宝藏"是什么类型

PYTHON 复制代码
from typing import Dict


# 学生成绩单
# 没有标签
scores = {"小明": 90, "小红": 95}


# 有标签(钥匙是名字,宝藏是分数)
scores: Dict[str, int] = {"小明": 90, "小红": 95}
# ↑ 标签上写着:钥匙是文字(str),宝藏是数字(int)

3. Optional - "也许有标签"

表示这个东西可能有,也可能没有

PYTHON 复制代码
from typing import Optional

# 小明的生日
# 没有标签
birthday = None  # 不知道生日
# 或者
birthday = "2000-01-01"

# 有标签(也许是日期,也许是空)
birthday: Optional[str] = None
# ↑ 标签上写着:可能是日期,也可能是"没有"

实际例子:班级管理

PYTHON 复制代码
from typing import Optional, List, Dict


class Student:
    """学生类"""
    
    def __init__(self, name: str, age: int):
        self.name: str = name  # 名字肯定是文字
        self.age: int = age    # 年龄肯定是数字
        self.phone: Optional[str] = None  # 电话可能有,可能没有
        self.scores: Dict[str, int] = {}  # 成绩单:科目->分数
        self.friends: List[str] = []      # 朋友列表:都是名字

class Class:
    """班级类"""
    
    def __init__(self, class_name: str):
        # 班级数据
        self.class_name: str = class_name
        self.students: List[Student] = []  # 学生列表:都是Student对象
        
    def add_student(self, student: Student) -> None:
        """添加学生"""
        self.students.append(student)
    
    def find_student(self, name: str) -> Optional[Student]:
        """查找学生"""
        for student in self.students:
            if student.name == name:
                return student
        return None  # 没找到就返回None
    
    def get_class_scores(self) -> Dict[str, Dict[str, int]]:
        """获取全班成绩"""
        scores_dict = {}
        for student in self.students:
            scores_dict[student.name] = student.scores
        return scores_dict


# 使用示例
if __name__ == "__main__":
    # 创建一个班级
    class_1 = Class("三年二班")
    
    # 创建几个学生
    xiaoming = Student("小明", 10)
    xiaoming.phone = "13800138000"  # 小明有电话
    xiaoming.scores = {"数学": 95, "语文": 88}
    xiaoming.friends = ["小红", "小刚"]
    
    xiaohong = Student("小红", 9)
    # 小红没有电话(phone是None)
    xiaohong.scores = {"数学": 90, "语文": 92}
    xiaohong.friends = ["小明"]
    
    # 把学生加入班级
    class_1.add_student(xiaoming)
    class_1.add_student(xiaohong)
    
    # 查找学生
    found_student = class_1.find_student("小明")
    if found_student:
        print(f"找到了:{found_student.name}")
    
    # 获取全班成绩
    all_scores = class_1.get_class_scores()
    print(f"全班成绩:{all_scores}")

更生活化的比喻

比喻1:超市购物清单

PYTHON 复制代码
from typing import List, Dict


# 购物清单
# 没有类型注解
shopping_list = [
    {"item": "苹果", "amount": 3, "price": 5.0},
    {"item": "牛奶", "amount": 2, "price": 8.5}
]


# 有类型注解(清晰多了!)
shopping_list: List[Dict[str, any]] = [
    {"item": "苹果", "amount": 3, "price": 5.0},
    {"item": "牛奶", "amount": 2, "price": 8.5}
]
# ↑ 意思:这是一个列表,里面每项都是字典

比喻2:通讯录

PYTHON 复制代码
from typing import List, Dict, Optional


# 通讯录里的联系人
class Contact:
    def __init__(
        self, 
        name: str,                     # 名字(肯定要有)
        phone: str,                    # 电话(肯定要有)
        email: Optional[str] = None,   # 邮箱(可能有,可能没有)
        groups: List[str] = None       # 分组(列表)
    ):
        self.name = name
        self.phone = phone
        self.email = email
        self.groups = groups or []
    
    def __str__(self) -> str:  # 返回值是字符串
        return f"{self.name}: {self.phone}"


# 通讯录
class AddressBook:
    def __init__(self):
        self.contacts: List[Contact] = []  # 联系人列表
    
    def add_contact(self, contact: Contact) -> None:
        self.contacts.append(contact)
    
    def find_by_name(self, name: str) -> Optional[Contact]:
        for contact in self.contacts:
            if contact.name == name:
                return contact
        return None


# 使用
my_book = AddressBook()
alice = Contact("Alice", "123456789", "alice@email.com", ["朋友", "同事"])
bob = Contact("Bob", "987654321")


my_book.add_contact(alice)
my_book.add_contact(bob)


found = my_book.find_by_name("Alice")
if found:
    print(found)

为什么要用 typing

对新手的好处:

  1. 一看就懂:代码更清晰,就像加了注释
  2. 减少错误:编辑器会提醒你类型错误
  3. 学习更快:理解别人代码更容易

实际体验不同点:

不用 typing(糊涂状态)

PYTHON 复制代码
def process(data):
    # 天呐!data是什么?列表?字典?数字?
    # 只能猜或者看代码逻辑
    return data * 2  # 这行代码对吗?不知道!

typing(清晰状态)

PYTHON 复制代码
def process(data: List[int]) -> List[int]:
    # 噢!data是数字列表,返回值也是数字列表
    # 所以 data * 2 可能不对(列表不能乘以2)
    return [x * 2 for x in data]  # 这样才对!
相关推荐
楚兴2 小时前
MacBook M1 安装 OpenClaw 完整指南
人工智能·后端
Java编程爱好者2 小时前
2026版Java面试八股文总结(春招+秋招+社招),建议收藏。
后端
朱昆鹏3 小时前
开源 Claude Code + Codex + 面板 的未来vibecoding平台
前端·后端·github
REDcker3 小时前
gRPC开发者快速入门
服务器·c++·后端·grpc
figo10tf3 小时前
Spring Boot项目集成Redisson 原始依赖与 Spring Boot Starter 的流程
java·spring boot·后端
zhangyi_viva3 小时前
Spring Boot(七):Swagger 接口文档
java·spring boot·后端
程序员敲代码吗3 小时前
Spring Boot与Tomcat整合的内部机制与优化
spring boot·后端·tomcat
牛奔3 小时前
如何理解 Go 的调度模型,以及 G / M / P 各自的职责
开发语言·后端·golang
chilavert3183 小时前
技术演进中的开发沉思-357:重排序(下)
java·后端