__init__ 是什么?
__init__ 是 Python 类中的一个特殊方法(也叫“魔术方法”或“Dunder Methods”,即 Double Underscore Methods),它的全称是 "initialize"(初始化)。
当你创建一个类的实例(也就是“对象”)时,Python 会自动调用这个 __init__ 方法,它的主要作用是初始化这个新创建的对象,为它的属性设置初始值。
__init__ 是对象的“构造函数”或“初始化器”。
__init__ 的基本语法和作用
让我们从一个最简单的例子开始。
class Dog:
# 这是一个特殊方法,当创建 Dog 类的实例时,会自动被调用
def __init__(self, name, age):
# self.name 和 self.age 是实例的属性
# name 和 age 是传入的参数
self.name = name
self.age = age
print(f"一只名叫 {self.name},年龄为 {self.age} 岁的小狗诞生了!")
# --- 创建实例 ---
# 当执行 dog1 = Dog("旺财", 2) 时:
# 1. Python 首先创建一个新的 Dog 对象。
# 2. 然后自动调用 Dog 类的 __init__ 方法。
# 3. 将新创建的对象本身作为第一个参数传递给 self。
# 4. 将 "旺财" 传递给 name 参数。
# 5. 将 2 传递给 age 参数。
dog1 = Dog("旺财", 2)
# --- 访问实例的属性 ---
print(f"小狗的名字是: {dog1.name}")
print(f"小狗的年龄是: {dog1.age}")
print("-" * 20)
# 创建另一个实例
dog2 = Dog("小白", 3)
print(f"小狗的名字是: {dog2.name}")
print(f"小狗的年龄是: {dog2.age}")
输出:
一只名叫 旺财,年龄为 2 岁的小狗诞生了!
小狗的名字是: 旺财
小狗的年龄是: 2
--------------------
一只名叫 小白,年龄为 3 岁的小狗诞生了!
小狗的名字是: 小白
小狗的年龄是: 3
核心概念详解
1 self 参数
self 是 __init__ 方法的第一个参数,也是最重要的参数。
- 它代表了类的实例本身。 当你创建一个对象
dog1 = Dog(...)时,dog1就被自动传递给了self。 - 通过
self,你可以访问实例的属性和方法。self.name就是当前实例的name属性,没有self,你就无法区分是设置哪个对象的属性。 - 命名约定: 按照惯例,
self这个名字是固定的,你也可以用别的名字(this),但这会极大地降低代码的可读性,强烈建议不要这样做。
你可以这样理解:
dog1.name = "旺财" 这句代码,在 __init__ 方法内部就是 self.name = "旺财",这里的 self 就指向了 dog1 这个对象。
2 __init__ 不是构造函数
这是一个非常重要的概念,也是一个常见的误区。
__new__才是真正的构造函数。__new__方法负责创建并返回一个对象实例,在绝大多数情况下,你不需要重写__new__方法,Python 的默认实现已经足够。__init__是初始化器。 它在__new__创建好对象之后被调用,负责对这个已经存在的对象进行初始化操作(比如设置属性)。
更准确的说法是:__new__ 负责创建,__init__ 负责初始化。
__init__ 的使用场景
__init__ 几乎用于所有类的定义中,主要用途包括:
- 设置初始属性值: 这是最常见的用途,如上面的
Dog类例子。 - 执行必要的初始设置: 比如打开一个文件、建立数据库连接、初始化一些复杂的数据结构等。
示例:一个银行账户类
class BankAccount:
def __init__(self, owner_name, initial_balance=0):
self.owner_name = owner_name
self.balance = initial_balance
print(f"账户 {self.owner_name} 已创建,初始余额为: ¥{self.balance:.2f}")
def deposit(self, amount):
if amount > 0:
self.balance += amount
print(f"存款 ¥{amount:.2f} 成功,当前余额: ¥{self.balance:.2f}")
else:
print("存款金额必须大于零。")
def check_balance(self):
return self.balance
# 创建账户,指定初始余额
account1 = BankAccount("张三", 1000)
# 创建账户,不指定初始余额(使用默认值 0)
account2 = BankAccount("李四")
# 进行操作
account1.deposit(500)
print(f"{account1.owner_name} 的当前余额是: ¥{account1.check_balance():.2f}")
输出:
账户 张三 已创建,初始余额为: ¥1000.00
账户 李四 已创建,初始余额为: ¥0.00
存款 ¥500.00 成功,当前余额: ¥1500.00
张三 的当前余额是: ¥1500.00
不使用 __init__ 会怎样?
如果一个类没有定义 __init__ 方法,Python 也能正常创建对象,只是这个对象在被创建时是“空”的,没有任何初始属性。
class EmptyClass:
pass # pass 表示一个空操作
# 创建实例
obj = EmptyClass()
# 尝试访问一个不存在的属性
# 这会抛出 AttributeError
try:
print(obj.name)
except AttributeError as e:
print(f"错误: {e}")
# 你可以事后动态地添加属性
obj.name = "临时添加的属性"
obj.age = 100
print(f"现在对象有了属性: name={obj.name}, age={obj.age}")
输出:
错误: 'EmptyClass' object has no attribute 'name'
现在对象有了属性: name=临时添加的属性, age=100
虽然可以这样做,但这通常被认为是不良的编程实践,因为它会导致对象的状态不明确,难以维护。__init__ 强制了对象在创建时就必须具备某些属性,保证了代码的健壮性和可预测性。
| 特性 | 描述 |
|---|---|
| 名称 | __init__ (前后各两个下划线) |
| 角色 | 初始化器,不是构造函数。 |
| 自动调用 | 在创建类的实例时,由 Python 自动调用。 |
| 第一个参数 | self,代表实例本身。 |
| 主要作用 | 为新创建的实例设置初始状态(属性)。 |
| 参数 | 除了 self 之外,你可以定义任意其他参数来接收创建实例时传入的值。 |
| 返回值 | __init__ 方法不应该返回任何值(即 return None)。 |
掌握 __init__ 是迈向 Python 面向对象编程的第一步,也是最重要的一步,它让你能够创建出行为和状态都清晰、可控的对象。
