Python 中的 __init__ 是什么? [With Examples]

想要开始使用Python进行面向对象编程吗?今天就从学习Python中的 __init__ 方法开始你的旅程。

在本指南中,我们将先回顾Python类和对象的基础知识,然后深入研究 __init__ 方法的细节。

学完本教程后,你将能够解答以下问题:

  • 什么是实例变量或实例属性?
  • __init__ 方法如何帮助初始化实例属性?
  • 如何为属性设置默认值?
  • 如何使用类方法作为构造器来创建对象?

让我们开始吧!

Python 类与对象

类是Python面向对象编程的核心。我们可以定义一个类,并在其中定义属性和方法,将数据和相关功能绑定在一起。

一旦我们创建了一个类,就可以将其用作蓝图(或模板)来创建对象(实例)。

👩‍🏫 举个例子!让我们创建一个 Employee 类,这个类的每个对象都应该具有以下属性:

  • full_name:员工的全名,格式为“名字 姓氏”。
  • emp_id:员工的唯一编号。
  • department:员工所在的部门。
  • experience:员工的工作年限。

这意味着什么呢? 🤔

每个员工都是 Employee 类的一个实例或对象。每个对象都有其自己的 full_nameemp_iddepartmentexperience 的值。

这些属性也被称为实例变量,我们将交替使用属性和实例变量这两个术语。

稍后我们会添加属性。现在,我们创建一个 Employee 类,如下所示:

class Employee:
    pass

使用 pass(作为占位符)有助于在运行脚本时避免错误。

虽然当前版本的 Employee 类不是很有用,但它仍然是一个有效的类。所以我们可以创建 Employee 类的对象:

employee_1 = Employee()

print(employee_1)
#输出: <__main__.Employee object at 0x00FEE7F0>

我们也可以添加属性并使用值初始化它们,如下所示:

employee_1.full_name="Amy Bell"
employee_1.department="HR"

但这种添加实例属性的方式既效率低下又容易出错。此外,这也不允许将类作为模板来创建对象。这就是 __init__ 方法的用武之地。

理解Python类中的__init__方法

我们应该能够在实例化对象时初始化实例变量,而 __init__ 方法可以帮助我们实现这一目标。每次创建类的新对象时都会调用 __init__ 方法来初始化实例变量的值。

如果你有使用C++等语言编程的经验,你会发现 __init__ 方法的工作方式类似于构造函数。

定义__init__方法

让我们将 __init__ 方法添加到 Employee 类:

class Employee:
    def __init__(self, full_name,emp_id,department,experience):
        self.full_name = full_name
        self.emp_id = emp_id
        self.department = department
        self.experience = experience

self 参数是指类的实例,self.attribute 将实例属性初始化为右侧的值。

我们现在可以像这样创建对象:

employee_2 = Employee('Bella Joy','M007','Marketing',3)
print(employee_2)
# 输出: <__main__.Employee object at 0x017F88B0>

当我们打印员工对象时,除了它们所属的类之外,我们没有得到任何有用的信息。让我们添加一个 __repr__ 方法来定义类的表示字符串:

 def __repr__(self):
        return f"{self.full_name},{self.emp_id} 来自 {self.department},拥有 {self.experience} 年的工作经验。"

__repr__ 添加到 Employee 类后,我们有:

class Employee:
    def __init__(self, full_name,emp_id,department,experience):
        self.full_name = full_name
        self.emp_id = emp_id
        self.department = department
        self.experience = experience
    
     def __repr__(self):
        return f"{self.full_name},{self.emp_id} 来自 {self.department},拥有 {self.experience} 年的工作经验。"

现在,员工对象有了一个有用的表示字符串:

print(employee_2)
# 输出: Bella Joy,M007 来自 Marketing,拥有 3 年的工作经验。

一些约定

在继续之前,这里有一些需要注意的事项:

  • 我们在 __init__ 方法中使用 self 作为第一个参数来引用类实例本身,并使用 self.attribute_name 来初始化各种属性。 使用 self 是首选约定(但你可以使用任何其他名称)。
  • 在定义 __init__ 方法时,我们通常将 __init__ 定义中的参数名称设置为与属性名称相匹配。这提高了代码的可读性。

如何为属性添加默认值

到目前为止,在我们编写的示例中,所有属性都是必需的。这意味着只有当我们为所有字段传递值给构造函数时,对象创建才会成功。

尝试在不传递 experience 属性值的情况下实例化 Employee 类的对象:

employee_3 = Employee('Jake Lee','E001','Engineering')

你会看到以下错误:

Traceback (most recent call last):
  File "main.py", line 22, in <module>
    employee_3 = Employee('Jake Lee','E001','Engineering')
TypeError: __init__() missing 1 required positional argument: 'experience'

但是,如果你希望某些属性是可选的,可以通过在定义 __init__ 方法时为这些属性提供默认值来实现。

在这里,我们为 experience 属性提供默认值 0:

class Employee:
    def __init__(self, full_name,emp_id,department,experience=0):
        self.full_name = full_name
        self.emp_id = emp_id
        self.department = department
        self.experience = experience
    
     def __repr__(self):
        return f"{self.full_name},{self.emp_id} 来自 {self.department},拥有 {self.experience} 年的工作经验。"

现在,创建的 employee_3 对象没有 experience 属性值;默认值 0 被用作 experience 的值。

employee_3 = Employee('Jake Lee','E001','Engineering')
print(employee_3.experience)
# 输出: 0

使用类方法的替代类构造函数

到目前为止,我们只了解了如何定义 __init__ 方法,以及如何在需要时为属性设置默认值。我们还知道需要在构造函数中传递所需属性的值。

然而,有时这些实例变量(或属性)的值可能在不同的数据结构中可用,例如元组、字典或 JSON 字符串。

那么我们应该怎么做呢?

让我们举个例子。假设我们在Python字典中有实例变量的值:

dict_fanny = {'name':'Fanny Walker','id':'H203','dept':'HR','exp':2}

我们可以访问字典并获取所有属性,如下所示:

name = dict_fanny['name']
id = dict_fanny['id']
dept = dict_fanny['dept']
exp = dict_fanny['exp']

之后,你可以通过将这些值传递给类构造函数来创建一个对象:

employee_4 = Employee(name, id, dept, exp)
print(employee_4)
# 输出: Fanny Walker,H203 来自 HR,拥有 2 年的工作经验。

请记住:你需要为创建的每个新对象都执行此操作。这种方法效率低下,我们绝对可以做得更好。但是该怎么做呢?

在Python中,我们可以使用类方法作为构造函数来创建类的对象。要创建类方法,我们使用 @classmethod 装饰器。

让我们定义一个方法来解析字典,获取实例变量值,并使用它们来构造 Employee 对象。

    @classmethod
    def from_dict(cls,data_dict):
        full_name = data_dict['name']
        emp_id = data_dict['id']
        department = data_dict['dept']
        experience = data_dict['exp']
        return cls(full_name, emp_id, department, experience)

当我们需要使用字典中的数据创建对象时,可以使用 from_dict() 类方法。

💡 注意,在类方法中使用 cls 而不是 self。就像我们使用 self 来引用实例一样,cls 用于引用类。此外,类方法绑定到类而不是对象。

所以,当我们调用类方法 from_dict() 来创建对象时,我们在 Employee 类上调用它:

emp_dict = {'name':'Tia Bell','id':'S270','dept':'Sales','exp':3}
employee_5 = Employee.from_dict(emp_dict)
print(employee_5)
# 输出: Tia Bell,S270 来自 Sales,拥有 3 年的工作经验。

现在,如果我们的 n 位员工中的每一位都对应一个字典,我们可以使用 from_dict() 类方法作为构造函数来实例化对象,而不必从字典中检索即时变量值。

📝 关于类变量的说明

在这里,我们定义了绑定到类而不是单个实例的类方法。与类方法类似,我们也可以拥有类变量。

与类方法一样,类变量绑定到类而不是实例。当一个属性对类的所有实例都取固定值时,我们可以考虑将它们定义为类变量。

常见问题

1. 为什么在Python中需要 __init__ 方法?

类定义中的 __init__ 方法允许我们初始化类的所有实例的属性或实例变量。每次创建类的新实例时都会调用 __init__ 方法。

2. 一个Python类中可以有多个 __init__ 方法吗?

在Python类中拥有多个 __init__ 方法的目的是提供多个实例化对象的构造函数。但是你不能定义多个 __init__ 方法。如果你定义多个 __init__ 方法,第二个(也是最近的)实现会覆盖第一个。但是,你可以使用 @classmethod 装饰器来定义可作为构造函数来实例化对象的类方法。

3. 如果不在类中定义 __init__ 方法会怎样?

如果你不定义 __init__ 方法,你仍然可以实例化对象。但是,你必须手动添加实例变量并为每个实例变量赋值。你将无法在构造函数中传递实例变量的值。这不仅容易出错,而且违背了将类作为蓝图,从中实例化对象的目的。

4. __init__ 方法中的参数可以有默认值吗?

是的,可以在定义 __init__ 方法时为一个或多个属性提供默认值。提供默认值有助于使这些属性在构造函数中变为可选。当我们不在构造函数中传递这些属性的值时,这些属性会采用默认值。

5. 你可以在 __init__ 方法之外修改属性吗?

是的,你始终可以在 __init__ 方法之外更新属性的值。你还可以在创建特定实例后向实例动态添加新属性。

结论

在本教程中,我们学习了如何使用 __init__ 方法来初始化实例变量的值。虽然这很简单,但可能很重复,尤其是在你有很多属性的时候。

如果你有兴趣,可以探索数据类模块。在Python 3.7及更高版本中,你可以使用内置的数据类模块来创建存储数据的数据类。除了 __init__ 和其他常用方法的默认实现外,它们还为类型提示、复杂的默认值和优化提供了很多很酷的功能。

接下来,详细了解Python中的 if __name__ == '__main__'