赋予一个轻量级的Python数据结构。
从Tuples到Namedtuples
利用命名图元的优势来管理你的数据
无论你用什么语言,做什么产品,你的程序都不可避免地要处理数据。作为一种通用的编程语言,Python 为我们提供了大量的内置数据类型,因此在如何存储、传递和更新我们程序中不同组件之间的数据方面给了我们很大的灵活性。
元组Tuple
当涉及到处理相关数据元素时,最常用的数据类型之一是元组。作为一种不可改变的数据类型,元组是具有固定大小的数据序列。它们对于将具有不同数据类型的相关数据分组很有用。考虑一下下面这个微不足道的例子。
employee0 = ('John Smith', 45, 'M', 160083)
在上面的代码片段中,我们定义了一个名为
employee0
的元组,它存储了一个雇员的个人数据,包括姓名、年龄、性别和雇员ID号。如果我们需要使用元组中的某些元素,我们可以将其解包或使用下标,其用法如下。
# 使用解包
name, age, gender, employee_id = employee0
print(f "Employee Name: {name}")
员工姓名:约翰-史密斯
>>> # Use unpacking
>>> name, age, gender, employee_id = employee0
>>> print(f"Employee Name: {name}")
Employee Name: John Smith
>>> # Use subscript
>>> print(f"Employee Age: {employee0[1]}")
Employee Age: 45
>>> print(f"Employee ID #: {employee0[-1]}")
Employee ID #: 160083
那我们需要在同一个模块中处理另一个雇员呢?我们必须做一些类似下面的事情。
创建一个元组来存储另一个雇员的数据
>>> # Create a tuple for storing another employee data
>>> employee1 = ('Jennifer Brown', 38, 'F', 150384)
>>>
>>> # Access data
>>> name1, age1, gender1, employee_id1 = employee1
>>> print(f"Employee Name: {employee1[0]}")
Employee Name: Jennifer Brown
>>> print(f"Employee Age: {age1}")
Employee Age: 38
>>> print(f"Employee ID #: {employee_id1}")
Employee ID #: 150384
实质上,我们必须重复上述步骤,并使用解包或下标来访问单个元素,这当然不是最令人愉快的事情。实际上,它可能会出错,因为你必须记住这些数据的确切顺序。
自定义类
有什么更好的解决方案吗?当然,你的第一直觉可能是创建一个自定义类来保存这些数据。这个解决方案会像下面这样。
定义一个自定义类
Class Employee:
... def __init__(self, name, age, gender, employee_id):
... self.name = name
... self.age = age
... self.gender = gender
... self.employee_id = employee_id
创建一个Employee类的实例
>>> employee2 = Employee('David Berger', 35, 'M', 134039)
>> # 访问数据
>> print(f "Employee Name: {employee2.name}" )
雇员姓名。大卫-伯杰
>> print(f "Employee Age: {employee2.age}")
员工年龄:35岁
>> print(f "雇员ID #: {employee2.employee_id}")
员工ID #: 134039
创建一个自定义类来管理这些雇员数据是绝对可以接受的。然而,声明和管理一个类有很多开销。对于我们的数据存储和读取目的来说,这有点麻烦。
此外,这些数据可能会被无意地改变,如下图所示。我们不希望这种情况发生,因为我们的目标是简单地保存员工的信息并方便地访问它们。
改变雇员的ID号
>>> employee2.employee_id = 500
>> print(f "雇员ID #: {employee2.employee_id}" )
雇员ID #: 500
命名元组
类和实例的创建
命名图元来拯救我们。通过命名图元,我们可以将特定的字段名分配给普通图元中的各个位置,这样我们的代码就更有可读性。在我们展开对命名图元的讨论之前,让我们看看我们如何构建它。
>>> from collections import namedtuple
>>>
>>> # 构建一个命名图元类
>>> Employee = namedtuple('Employee', ['name', 'age', 'gender', 'employee_id'])
>>>
>> # 创建一个实例
>>> Employee = Employee('Ann Luck', 28, 'F', 193080)
>>>
>>> # 自省
>>> type(employee)
<类 '__main__.Employee'>
>>> isinstance(employee, Employee)
真
>>> isinstance(employee, tuple)
真
在上面的代码片断中,有几件事需要注意。
namedtuple
类型在集合模块中是可用的。
我们使用工厂函数namedtuple()
来构造Employee类,该函数接收一个字符串作为类名,以及一个字符串列表来表示该类的字段。
一旦namedtuple
类被创建,我们就可以像之前那样,像对待普通的自定义类那样,创建一个实例对象。
实例对象(即Employee)的类型是Employee类。此外,Employee类是元组数据类型的一个子类,因此对象employee也是元组的一个实例。
我们已经创建了上面的类和实例对象。现在用点符号访问个人的属性就更直接了,就像我们对自定义类所做的那样,如下所示。
>> # 创建一个实例
>>> employee01 = Employee('Bella Jones', 42, 'F', 178394)
>>>
>> # 访问数据
>> print(f "Employee Name: {employee01.name}" )
员工姓名。Bella Jones
>> print(f "Employee Age: {employee01.age}")
员工年龄:42岁
>> print(f "雇员ID #: {employee01.employee_id}")
员工ID #: 178394
数据操作
尽管我们表明namedtuples
是tuples
的一个子类,但它实际上是一个比tuples更灵活的数据类型,具有额外的数据操作方法。
最常见的方法是_make
, _asdict
, 和_replace
。让我们回顾一下这些方法,看看它们各自的用法,如下。
classmethod
somenamedtuple._make(iterable)
这是一个类方法,使用现有的iterable创建命名的tuple实例对象。
>> #实例来自一个元组
>>> t0 = ('Bella Jones', 42, 'F', 178394)
>>> employee_t0 = Employee._make(t0)
>> # 从一个列表的实例
>> t1 = ['Jerry Dani', 38, 'M', 170438] 。
>>> employee_t1 = Employee._make(t1)
somenamedtuple._asdict()
这是一个实例方法,它创建了一个实例对象的字典呈现。有一点需要注意的是,这个函数的返回值在不同版本的 Python 之间发生了变化。
在 Python 3.7 中,返回的类型是 OrderedDict,但在 Python 3.8 以上,返回的类型是 dict。尽管如此,我们可以使用dict()构造函数方便地将OrderedDict转换为dict。
创建一个实例
>>> employee02 = Employee('Cathy Bradley', 44, 'F', 180030)
>>> # 获取字典的表示方法
>>> employee02._asdict()
OrderedDict([('name', 'Cathy Bradley'), ('age', 44), ('gender', 'F'), ('employee_id', 180030)] )
>> # 将其转换为一个常规的dict
>>> dict(employee02._asdict())
{'name': 'Cathy Bradley', 'age': 44, '性别': 'F', 'employee_id': 180030}
somenamedtuple._replace(**kwargs)
这是一个实例方法,返回一个新的实例对象,用新的值替换指定的字段。有一点需要注意的是,由于元组的不可更改性,替换一个字段不会更新原始的元组对象。如下图所示,我们更新了对象Employee03的年龄,但是当我们检查年龄时,它仍然是原来的值58
>> # 创建一个实例
>>> employee03 = Employee('David Bradley', 58, 'M', 150030)
>> # 替换年龄
>>> employee03._replace(age=59)
Employee(name='David Bradley', age=59, gender='M', employee_id=150030)
>>> employee03.age
58
>> # 通过替换年龄创建一个新的实例
>>> employee03 = employee03._replace(age=59)
>>> dict(employee03._asdict())
{'name': 'David Bradley', 'age': 59, '性别': 'M', 'employee_id': 150030}
结论
在这篇文章中,我们回顾了nametuples作为一种轻量级的替代数据结构来处理数据。从本质上讲,它们可以被用于任何适用于常规图元的地方。重要的是,它们允许我们通过名字而不是元素的索引来访问字段,这一特性使我们的代码更容易阅读。
补充阅读列表
有几个概念与本文有关,包括图元、数据可变性,当然还有nametuples。如果你想了解更多关于这些主题的信息,下面的参考资料是为了方便你。
本文由mdnice多平台发布
网友评论