想要开始使用Python进行面向对象编程吗?今天就从学习Python中的 __init__
方法开始你的旅程。
在本指南中,我们将先回顾Python类和对象的基础知识,然后深入研究 __init__
方法的细节。
学完本教程后,你将能够解答以下问题:
- 什么是实例变量或实例属性?
__init__
方法如何帮助初始化实例属性?- 如何为属性设置默认值?
- 如何使用类方法作为构造器来创建对象?
让我们开始吧!
Python 类与对象
类是Python面向对象编程的核心。我们可以定义一个类,并在其中定义属性和方法,将数据和相关功能绑定在一起。
一旦我们创建了一个类,就可以将其用作蓝图(或模板)来创建对象(实例)。
👩🏫 举个例子!让我们创建一个 Employee
类,这个类的每个对象都应该具有以下属性:
full_name
:员工的全名,格式为“名字 姓氏”。emp_id
:员工的唯一编号。department
:员工所在的部门。experience
:员工的工作年限。
这意味着什么呢? 🤔
每个员工都是 Employee
类的一个实例或对象。每个对象都有其自己的 full_name
、emp_id
、department
和 experience
的值。
这些属性也被称为实例变量,我们将交替使用属性和实例变量这两个术语。
稍后我们会添加属性。现在,我们创建一个 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__'
。