第53集:构造方法 __init__
学习目标
- 理解
__init__方法的作用和调用时机 - 掌握
__init__方法的定义和使用 - 学会为对象初始化属性
- 理解默认参数在
__init__中的应用 - 掌握对象创建的完整流程
- 学会避免常见的初始化错误
一、什么是构造方法
1.1 构造方法的定义
构造方法:是一个特殊的方法,在创建对象时自动调用,用于初始化对象的属性。
在Python中,构造方法的名称是固定的:__init__
1.2 构造方法的作用
┌─────────────────────────────────────────┐
│ 创建对象的过程 │
├─────────────────────────────────────────┤
│ 1. 分配内存空间 │
│ 2. 调用 __init__ 方法 │
│ ↓ │
│ 初始化对象的属性 │
│ 3. 返回对象引用 │
└─────────────────────────────────────────┘1.3 为什么需要构造方法
没有构造方法的问题:
class Person:
def introduce(self):
print(f"我叫{self.name},今年{self.age}岁")
p = Person()
# 需要手动设置属性
p.name = "张三"
p.age = 18
p.introduce()有构造方法的好处:
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
def introduce(self):
print(f"我叫{self.name},今年{self.age}岁")
# 创建对象时直接初始化
p = Person("张三", 18)
p.introduce()二、__init__方法的基本语法
2.1 语法格式
class ClassName:
def __init__(self, 参数1, 参数2, ...):
# 初始化代码
self.属性1 = 参数1
self.属性2 = 参数2
...2.2 基本示例
class Student:
def __init__(self, name, age, grade):
"""初始化学生对象"""
self.name = name
self.age = age
self.grade = grade
# 创建对象时,自动调用__init__方法
s = Student("张三", 18, "大一")
print(s.name) # 输出:张三
print(s.age) # 输出:18
print(s.grade) # 输出:大一2.3 参数传递机制
class Point:
def __init__(self, x, y):
self.x = x
self.y = y
# 创建对象时传入参数
p = Point(10, 20)
# 参数传递过程:
# Point(10, 20) -> __init__(self, 10, 20)
# self.x = 10, self.y = 20三、__init__方法详解
3.1 self参数
self的含义:
self代表当前正在创建的对象- Python自动传递,不需要手动传递
class Demo:
def __init__(self, value):
print(f"self的值: {self}")
print(f"self的类型: {type(self)}")
self.value = value
d = Demo(100)
# 输出:
# self的值: <__main__.Demo object at 0x...>
# self的类型: <class '__main__.Demo'>3.2 参数类型
3.2.1 必需参数
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
# 必须提供所有参数
p = Person("张三", 18) # 正确
# p = Person("张三") # 错误:缺少age参数3.2.2 默认参数
class Person:
def __init__(self, name, age=18):
self.name = name
self.age = age
# 可以只提供必需的参数
p1 = Person("张三") # age使用默认值18
p2 = Person("李四", 20) # age使用指定值20
print(f"{p1.name}: {p1.age}") # 输出:张三: 18
print(f"{p2.name}: {p2.age}") # 输出:李四: 203.2.3 可变参数
class Numbers:
def __init__(self, *numbers):
self.numbers = list(numbers)
n = Numbers(1, 2, 3, 4, 5)
print(n.numbers) # 输出:[1, 2, 3, 4, 5]3.2.4 关键字参数
class Person:
def __init__(self, name, age, **info):
self.name = name
self.age = age
self.info = info
p = Person("张三", 18, city="北京", job="程序员")
print(p.info) # 输出:{'city': '北京', 'job': '程序员'}四、__init__方法的使用场景
4.1 初始化基本属性
class Car:
def __init__(self, brand, model, year, color):
self.brand = brand
self.model = model
self.year = year
self.color = color
car = Car("Toyota", "Camry", 2024, "白色")4.2 初始化复杂数据结构
class Library:
def __init__(self):
self.books = [] # 书籍列表
self.members = {} # 成员字典
self.borrowed = {} # 借阅记录
library = Library()4.3 初始化并计算
class Circle:
pi = 3.14159
def __init__(self, radius):
self.radius = radius
self.area = self.pi * radius ** 2 # 计算面积
self.circumference = 2 * self.pi * radius # 计算周长
circle = Circle(5)
print(circle.area) # 输出:78.53975
print(circle.circumference) # 输出:31.41594.4 参数验证
class AgeValidator:
def __init__(self, age):
if age < 0 or age > 150:
raise ValueError("年龄必须在0-150之间")
self.age = age
try:
person = AgeValidator(200) # 会报错
except ValueError as e:
print(e) # 输出:年龄必须在0-150之间4.5 引用其他对象
class Engine:
def __init__(self, power):
self.power = power
class Car:
def __init__(self, brand, engine_power):
self.brand = brand
self.engine = Engine(engine_power) # 创建Engine对象
car = Car("Toyota", 200)
print(car.engine.power) # 输出:200五、默认参数的应用
5.1 简单默认参数
class Person:
def __init__(self, name, age=18, gender="未知"):
self.name = name
self.age = age
self.gender = gender
p1 = Person("张三")
p2 = Person("李四", 20)
p3 = Person("王五", 22, "男")5.2 复杂默认参数
class BankAccount:
def __init__(self, account_number, owner, balance=0, currency="CNY"):
self.account_number = account_number
self.owner = owner
self.balance = balance
self.currency = currency
self.transactions = [] # 交易记录
account1 = BankAccount("001", "张三")
account2 = BankAccount("002", "李四", 1000)
account3 = BankAccount("003", "王五", 500, "USD")5.3 使用None作为默认参数
class Person:
def __init__(self, name, phone=None):
self.name = name
self.phone = phone if phone else "未设置"
p1 = Person("张三")
p2 = Person("李四", "13800138000")
print(p1.phone) # 输出:未设置
print(p2.phone) # 输出:13800138000注意:避免使用可变对象作为默认参数
# 错误示例:使用列表作为默认参数
class BadExample:
def __init__(self, items=[]): # 错误!
self.items = items
# 正确示例:使用None
class GoodExample:
def __init__(self, items=None):
if items is None:
items = []
self.items = items六、对象创建的完整流程
6.1 详细流程图
创建对象: obj = ClassName(参数1, 参数2, ...)
↓
1. Python解释器分配内存空间
↓
2. 调用 __new__ 方法创建对象
↓
3. 调用 __init__ 方法初始化对象
↓
4. 返回对象引用
↓
5. 变量 obj 指向该对象6.2 __new__ vs __init__
| 特性 | __new__ |
__init__ |
|---|---|---|
| 作用 | 创建对象 | 初始化对象 |
| 参数 | cls, *args, **kwargs | self, *args, **kwargs |
| 返回值 | 返回对象 | 不返回值(或返回None) |
| 调用顺序 | 先调用 | 后调用 |
| 常用性 | 很少重写 | 经常重写 |
示例:
class Demo:
def __new__(cls, *args, **kwargs):
print("__new__被调用")
return super().__new__(cls)
def __init__(self, value):
print("__init__被调用")
self.value = value
d = Demo(100)
# 输出:
# __new__被调用
# __init__被调用6.3 内存分配示意
内存空间
┌────────────────────────────┐
│ 对象地址: 0x1000 │
│ ┌──────────────────────┐ │
│ │ name: "张三" │ │
│ │ age: 18 │ │
│ │ ...其他属性 │ │
│ └──────────────────────┘ │
└────────────────────────────┘
↑
│
obj = Person("张三", 18)七、综合示例
7.1 学生类完整示例
class Student:
"""学生类"""
# 类属性
school = "Python大学"
total_students = 0
def __init__(self, student_id, name, age, grade, scores=None):
"""初始化学生"""
self.student_id = student_id
self.name = name
self.age = age
self.grade = grade
self.scores = scores if scores else {}
Student.total_students += 1
def add_score(self, subject, score):
"""添加成绩"""
self.scores[subject] = score
def get_average(self):
"""计算平均分"""
if not self.scores:
return 0
return sum(self.scores.values()) / len(self.scores)
# 创建学生
s1 = Student("001", "张三", 18, "大一")
s2 = Student("002", "李四", 19, "大二", {"数学": 90, "英语": 85})
s1.add_score("Python", 88)
s1.add_score("数学", 92)
print(f"{s1.name}的平均分: {s1.get_average()}")
print(f"{s2.name}的平均分: {s2.get_average()}")7.2 银行账户示例
class BankAccount:
"""银行账户类"""
def __init__(self, account_number, owner,
initial_balance=0, currency="CNY"):
"""初始化账户"""
if initial_balance < 0:
raise ValueError("初始余额不能为负数")
self.account_number = account_number
self.owner = owner
self.balance = initial_balance
self.currency = currency
self.transactions = []
if initial_balance > 0:
self._record_transaction("初始存款", initial_balance)
def _record_transaction(self, type_, amount):
"""记录交易(私有方法)"""
self.transactions.append({
"type": type_,
"amount": amount,
"balance": self.balance
})
def deposit(self, amount):
"""存款"""
if amount <= 0:
raise ValueError("存款金额必须大于0")
self.balance += amount
self._record_transaction("存款", amount)
def withdraw(self, amount):
"""取款"""
if amount <= 0:
raise ValueError("取款金额必须大于0")
if amount > self.balance:
raise ValueError("余额不足")
self.balance -= amount
self._record_transaction("取款", -amount)
# 创建账户
account = BankAccount("6222000012345678", "张三", 1000)
account.deposit(500)
account.withdraw(200)
print(f"余额: {account.balance}")
print(f"交易记录: {account.transactions}")八、常见错误与注意事项
8.1 常见错误
- 忘记self参数:
class Person:
def __init__(name, age): # 错误:缺少self
self.name = name
self.age = age- 使用可变对象作为默认参数:
class Person:
def __init__(self, name, hobbies=[]): # 错误!
self.name = name
self.hobbies = hobbies- 忘记初始化属性:
class Person:
def __init__(self, name, age):
self.name = name
# 忘记初始化age
p = Person("张三", 18)
print(p.age) # 报错:AttributeError- 在__init__中返回值:
class Person:
def __init__(self, name):
self.name = name
return self # 错误:__init__不应该返回值8.2 注意事项
__init__方法名是固定的:必须是__init__,前后各两个下划线- 第一个参数必须是self:代表当前对象
- 避免使用可变对象作为默认参数:使用None代替
- 可以进行参数验证:在
__init__中验证参数的合法性 - 可以调用其他方法:在
__init__中可以调用实例方法辅助初始化
九、课后练习
练习题
编程题
- 定义一个
Rectangle类,在__init__中初始化长和宽 - 添加计算面积和周长的方法
- 使用默认参数
- 定义一个
编程题
- 定义一个
Book类,包含书名、作者、价格、出版年份 - 使用关键字参数
- 添加参数验证(价格必须大于0)
- 定义一个
编程题
- 定义一个
GameCharacter类 - 包含姓名、生命值、攻击力
- 生命值默认100,攻击力默认20
- 添加方法验证生命值范围
- 定义一个
思考题
__init__方法和普通方法有什么区别?- 为什么
__init__方法需要self参数? - 什么时候应该在
__init__中进行参数验证?
十、本集总结
核心知识点回顾
__init__方法:构造方法,创建对象时自动调用- 作用:初始化对象的属性
- 参数:第一个参数必须是self
- 默认参数:可以为参数设置默认值
- 参数验证:在
__init__中验证参数的合法性 - 避免错误:不使用可变对象作为默认参数
下集预告
下一集我们将学习实例方法与self,深入了解如何使用self访问和操作对象的属性与方法。
学习建议: 熟练掌握__init__方法的使用,理解对象创建的完整过程。尝试编写不同类型的类,练习参数验证和默认参数的使用。