Pythonnamedtuple(将元组提升到一个新的水平)

2023-10-25

在本教程中,我们将深入研究命名元组:它们是什么,如何创建和操作它们,以及何时使用它们(或不使用它们)。

命名元组是Python内置的一部分收藏模块,并且它们提供了一种将数据捆绑在一个名称下的便捷方法。

它们是 Python 内置元组数据类型的子类,但有一个特点:命名元组是元组,其中每个值(或“字段”)也可以通过唯一的、用户定义的名称进行访问。

当您需要以结构化、不可变的格式将相关数据分组在一起时,命名元组是一个不错的选择。

 

 

创建命名元组

在 Python 中创建命名元组涉及namedtuple()用于创建元组子类的工厂函数。

nametuple 需要一个类型名和一个字段名作为其参数。类型名称将是新类的名称。

字段名称可以作为可迭代的字符串或单个空格/逗号分隔的字符串提供。


from collections import namedtuple

# Define a Car namedtuple
Car = namedtuple('Car', 'brand model year color')

# Instantiate a Car
my_car = Car('Tesla', 'Model S', 2023, 'Red')
print(my_car)
  

Output:


Car(brand='Tesla', model='Model S', year=2023, color='Red')
  

在此代码中,我们从集合模块导入namedtuple类,并定义一个带有字段名称“brand”、“model”、“year”和“color”的Carnamedtuple。

然后,我们通过传递适当的值来构造 Car 命名元组的实例。

添加默认值

从 Python 3.7 开始,namedtuple 函数包含一个 defaults 关键字参数来提供默认值。


# Define a Car namedtuple with default color and year
Car = namedtuple('Car', 'brand model year color', defaults=('Unknown', 'Black'))

# Instantiate a Car without providing color and year
my_car = Car('Tesla', 'Model S')

print(my_car)
  

Output:


Car(brand='Tesla', model='Model S', year='Unknown', color='Black')
  

在上面的示例中,我们为“年份”和“颜色”字段提供了默认值。

当我们创建一个新的 Car 命名元组而不指定这些字段时,将使用默认值。

 

访问元素

一旦我们有了命名元组,我们就可以通过几种不同的方式访问它的元素。

使用索引

尽管命名元组通过添加字段名称改进了常规元组,但我们仍然可以使用索引访问元素,就像常规元组一样。


from collections import namedtuple

# Define a Fruit namedtuple
Fruit = namedtuple('Fruit', ['name', 'color'])

# Create an instance of Fruit
apple = Fruit('Apple', 'Red')

print(apple[0])  # Access element by index
  

Output:


Apple
  

在此示例中,我们使用索引 0 访问水果的名称。

使用字段名称(使用点表示法)

命名元组的主要功能之一是能够使用字段名称访问元素。这通常是使用点表示法来完成的。


print(apple.name)
  

Output:


Apple
  

在这里,我们使用水果的字段名称来访问水果的名称。

使用 getattr()

Python 的内置getattr()函数允许我们访问对象属性的值。对于命名元组,我们可以使用它来访问字段值。


print(getattr(apple, 'color'))
  

Output:


Red
  

 

修改namedtuple(使用_replace()方法)

由于命名元组是不可变的,我们不能直接修改它们。

但有一个解决方法,使用_replace()方法,它返回一个带有替换字段的新实例。


from collections import namedtuple
Point = namedtuple('Point', ['x', 'y'])
p = Point(10, 20)

# Modify the y-coordinate
p = p._replace(y=30)
print(p)
  

Output:


Point(x=10, y=30)
  

在此示例中,我们将点的 y 坐标从 20 替换为 30。

将namedtuple转换为字典

要将命名元组转换为字典,请使用_asdict()方法。当您需要来自命名元组的键值对时,这非常有用。


d = p._asdict()
print(d)
  

Output:


{'x': 10, 'y': 30}
  

在这里,我们将命名元组转换为字典,其中字段名称作为键,相应的值作为值。

使用 _fields 方法

The _fields属性返回一个列出字段名称的元组。当您需要迭代命名元组的所有字段时,它会很有用。


print(Point._fields)
  

Output:


('x', 'y')
  

在这里,我们打印点命名元组的字段名称。

使用_make

The _make()方法允许我们从可迭代对象创建一个命名元组的新实例。


data = [100, 200]
new_point = Point._make(data)
print(new_point)
  

Output:


Point(x=100, y=200)
  

我们使用以下方法从值列表中创建一个名为tuple的新点_make() method.

 

迭代命名元组

您可以像使用常规元组一样迭代命名元组。就是这样:


from collections import namedtuple
Person = namedtuple('Person', ['name', 'age', 'city'])

# Create an instance of the namedtuple
person = Person('John Doe', 30, 'New York')

# Iterate over the namedtuple
for field in person:
    print(field)
  

Output:


John Doe
30
New York
  

在上面的代码中,我们定义了一个namedtuplePerson并创建一个实例person。然后我们迭代person使用简单的 for 循环,打印命名元组中的每个字段。

迭代字段名称和值

如果您想迭代字段名称和值,可以将namedtuple转换为字典并使用items() method:


from collections import namedtuple
Person = namedtuple('Person', ['name', 'age', 'city'])
p = Person('John Doe', 30, 'New York')
for field_name, field_value in p._asdict().items():
    print(f"{field_name}: {field_value}")
  

Output:


name: John Doe
age: 30
city: New York
  

在此代码中,我们使用_asdict()方法将namedtuple转换为字典,然后使用items()方法来获取字段名称和值对。

使用 _fields() 和 getattr()

您还可以使用_fields方法结合getattr()迭代两个字段名称及其相应的值:


from collections import namedtuple
Person = namedtuple('Person', ['name', 'age', 'city'])
p = Person('John Doe', 30, 'New York')
for field_name in p._fields:
    print(f"{field_name}: {getattr(p, field_name)}")
  

Output:


name: John Doe
age: 30
city: New York
  

在这里,_fields方法提供字段名称,以及getattr()用于从每个字段中获取相应的值person命名元组。

 

对命名元组进行排序

您可以对命名元组列表进行排序,类似于对元组列表进行排序。排序基于字段的自然顺序。

但是,您可以使用以下命令自定义排序itemgetter函数从operator module.


from collections import namedtuple
from operator import itemgetter
Fruit = namedtuple('Fruit', ['name', 'color'])

# Create a list of fruits
fruits = [Fruit('Apple', 'Red'), Fruit('Banana', 'Yellow'), Fruit('Cherry', 'Red')]

# Sort the list of fruits by color
sorted_fruits = sorted(fruits, key=itemgetter(1))
for fruit in sorted_fruits:
    print(fruit)
  

Output:


Fruit(name='Apple', color='Red')
Fruit(name='Cherry', color='Red')
Fruit(name='Banana', color='Yellow')
  

在此示例中,我们定义一个名为 tuple 的 Fruit 并创建一个 Fruit 实例列表。然后,我们使用“颜色”字段对该列表进行排序itemgetter功能。

 

命名元组与元组、列表和字典

让我们比较一下这些数据类型的效率。

我们的基准测试将重点关注这些数据结构的创建、内存使用和简单访问。

我们可以采取以下方法:

  1. 我们将创建一个 Namedtuple、Tuple、List 和 Dictionary,每个都包含相同的元素。
  2. 我们将测量创建每个结构所需的时间。
  3. 我们将测量每个结构的内存使用情况。
  4. 我们将测量访问每个结构中的元素所需的时间。

import sys
import timeit
from collections import namedtuple

# The size of the data structure
SIZE = 1000000
data = [(i, 'data{}'.format(i)) for i in range(SIZE)]

# Define the namedtuple type
DataNT = namedtuple('DataNT', 'id value')

# Conversion factor from seconds to milliseconds
SEC_TO_MSEC = 1000

# Create and measure time and memory for tuple
start = timeit.default_timer()
tuple_data = tuple(data)
tuple_time = (timeit.default_timer() - start) * SEC_TO_MSEC
tuple_mem = sys.getsizeof(tuple_data)

# Create and measure time and memory for namedtuple
start = timeit.default_timer()
namedtuple_data = tuple(DataNT(*d) for d in data)
namedtuple_time = (timeit.default_timer() - start) * SEC_TO_MSEC
namedtuple_mem = sys.getsizeof(namedtuple_data)

# Create and measure time and memory for list
start = timeit.default_timer()
list_data = list(data)
list_time = (timeit.default_timer() - start) * SEC_TO_MSEC
list_mem = sys.getsizeof(list_data)

# Create and measure time and memory for dictionary
start = timeit.default_timer()
dict_data = dict(data)
dict_time = (timeit.default_timer() - start) * SEC_TO_MSEC
dict_mem = sys.getsizeof(dict_data)

# Access and measure time for tuple
start = timeit.default_timer()
_ = tuple_data[SIZE//2]
tuple_access_time = (timeit.default_timer() - start) * SEC_TO_MSEC

# Access and measure time for namedtuple
start = timeit.default_timer()
_ = namedtuple_data[SIZE//2]
namedtuple_access_time = (timeit.default_timer() - start) * SEC_TO_MSEC

# Access and measure time for list
start = timeit.default_timer()
_ = list_data[SIZE//2]
list_access_time = (timeit.default_timer() - start) * SEC_TO_MSEC

# Access and measure time for dictionary
start = timeit.default_timer()
_ = dict_data[SIZE//2]
dict_access_time = (timeit.default_timer() - start) * SEC_TO_MSEC


results = {
    "tuple": {"creation_time_ms": tuple_time, "memory": tuple_mem, "access_time_ms": tuple_access_time},
    "namedtuple": {"creation_time_ms": namedtuple_time, "memory": namedtuple_mem, "access_time_ms": namedtuple_access_time},
    "list": {"creation_time_ms": list_time, "memory": list_mem, "access_time_ms": list_access_time},
    "dict": {"creation_time_ms": dict_time, "memory": dict_mem, "access_time_ms": dict_access_time},
}
print(results)
  

基准测试结果:

Data Structure Creation Time (ms) Memory Usage (bytes) Access Time (ms)
Tuple 13.2023 8000040 0.0022
NamedTuple 1601.5981 8000040 0.0016
List 12.2202 8000056 0.0013
Dictionary 74.7433 41943136 0.0021

列表和命名元组提供对元素的最快访问。这是因为它们将元素存储在连续的内存块中。

 

类中的命名元组

命名元组可以在类中使用,以增强代码的可读性和组织性。让我们创建一个使用命名元组的类。


from collections import namedtuple
Person = namedtuple('Person', ['name', 'age'])

class Classroom:
    def __init__(self):
        self.students = []

    def add_student(self, name, age):
        student = Person(name, age)
        self.students.append(student)

classroom = Classroom()
classroom.add_student('John', 16)
classroom.add_student('Emma', 17)
for student in classroom.students:
    print(student)
  

Output:


Person(name='John', age=16)
Person(name='Emma', age=17)
  

在此示例中,我们有一个 Classroom 类,它使用 Person 命名元组来存储有关学生的信息。

add_student 方法创建一个名为tuple 的新 Person 并将其添加到学生列表中。

 

函数中的命名元组

命名元组可以从函数返回,这可以通过为元组的元素命名来提高代码的可读性。

让我们创建一个返回命名元组的函数。


from collections import namedtuple
Result = namedtuple('Result', ['success', 'data'])
def fetch_data():
    data = "sample data"
    success = True
    return Result(success, data)
result = fetch_data()
print(result)
  

Output:


Result(success=True, data='sample data')
  

在这里,我们有一个 fetch_data 函数,它返回一个名为 tuple 的结果,其中包含一个指示数据获取是否成功的布尔值以及数据本身。

 

嵌套命名元组

命名元组还可以嵌套以创建更复杂的数据结构。这可以提高代码的可读性。


from collections import namedtuple
Address = namedtuple('Address', ['street', 'city', 'state', 'zip_code'])
Person = namedtuple('Person', ['name', 'age', 'address'])

# Create an Address instance
home_address = Address('123 Main St', 'Springfield', 'IL', '62701')

# Create a Person instance with a nested Address
person = Person('John Doe', 30, home_address)
print(person)
  

Output:


Person(name='John Doe', age=30, address=Address(street='123 Main St', city='Springfield', state='IL', zip_code='62701'))
  

在此示例中,我们定义了一个名为地址的元组和一个包含地址字段的个人名为元组。

这允许我们将 Address 实例嵌套在 Person 实例中,从而创建更加结构化和可读的数据表示。

 

命名元组与元组

下面是Python中namedtuple和tuple的对比表。

Aspect namedtuple tuple
Access method By field name or index or using getattr() By index only
Code readability High (each value has a name) Low (need to remember order of values)
Memory usage More than tuples (due to metadata) Less than namedtuples
Flexibility Fixed once defined Can include any values
Can be used as dict key Yes Yes
Mutability Immutable Immutable
Method support Has several helpful methods Has only count() and index() methods

 

命名元组与数据类

下面是Python中namedtuple和dataclass的对比表。

Aspect namedtuple dataclass
Introduced in Python 2.6 Python 3.7
Access method By field name or index By field name
Mutability Immutable Both mutable and immutable versions
Default values Not supported natively Supported
Methods Few built-in methods Can define custom methods
Inheritance Can be extended using subclasses Supports standard Python inheritance
Code readability High (each value has a name) High (each value has a name)
Memory usage Less than dataclasses More than namedtuples
Type hints Not supported natively Supported
Usage Better for simpler use cases Better for complex use cases

 

何处使用命名元组的实际示例

分组数据和记录:命名元组是将相关数据分组在一起的有效方法。

例如,如果您有与汽车相关的各种数据(例如型号、品牌、年份和颜色),则可以将这些数据分组到命名元组中。


from collections import namedtuple
Car = namedtuple('Car', ['make', 'model', 'year', 'color'])
car = Car('Toyota', 'Camry', 2018, 'Blue')
print(car)
  

Output:


Car(make='Toyota', model='Camry', year=2018, color='Blue')  

在此示例中,Carnamedtuple 用于对与特定汽车相关的数据进行分组。

从函数返回多个值:Python 中的函数可以返回多个值,并且通常这些值作为元组返回。

使用命名元组而不是常规元组可以为返回值提供更多上下文,从而提高可读性。


from collections import namedtuple
from math import pi
CircleMetrics = namedtuple('CircleMetrics', ['area', 'circumference'])
def calculate_circle_metrics(radius):
    area = pi * radius * radius
    circumference = 2 * pi * radius
    return CircleMetrics(area, circumference)
metrics = calculate_circle_metrics(5)
print(metrics)
  

Output:


CircleMetrics(area=78.53981633974483, circumference=31.41592653589793)  

在这个例子中,函数calculate_circle_metrics计算圆的面积和周长并返回包含这两个值的 CircleMetrics 命名元组。

 

何时不使用命名元组的示例

虽然命名元组很有用且用途广泛,但在某些情况下其他数据结构可能更适合。

  • 当数据需要可变时:由于命名元组是不可变的,因此如果您需要可以修改值的数据结构,那么它们不适合。在这种情况下,字典或列表可能更合适。
  • 当您需要更复杂的数据结构时:虽然命名元组可以嵌套,但如果您需要更复杂或自定义的数据结构,则可能需要定义自己的类。

例如,让我们举一个例子,我们想要代表一个学生,我们需要动态添加科目。在这种情况下,字典将是更合适的选择。


student = {
    'name': 'John Doe',
    'age': 16,
    'subjects': ['English', 'Math', 'Science']
}

# Add a new subject
student['subjects'].append('History')
print(student)
  

Output:


{'name': 'John Doe', 'age': 16, 'subjects': ['English', 'Math', 'Science', 'History']}  

在此示例中,学生的科目存储在字典内的列表中,允许您动态添加或删除科目。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Pythonnamedtuple(将元组提升到一个新的水平) 的相关文章

随机推荐

  • 如何在 Ubuntu 16.04 LTS 上安装 Swift

    Swift 是一种安全 快速 富有表现力的通用编程语言 专为软件设计模式而构建 它最适合系统编程 移动和桌面应用程序 Swift 提供了大量功能 使编程变得更加容易 同时为开发人员提供了真正的系统编程语言所需的控制能力 本教程将帮助您在 U
  • 如何在 Fedora Linux 上安装 Git

    Git 是一个分布式版本控制系统 广泛应用于软件开发和其他协作项目 在本指南中 我们将介绍在 Fedora Linux 上安装 Git 的两种方法 使用官方存储库和从最新源代码编译 先决条件 确保您有一个运行 Fedora Linux 的系
  • 如何在 Python 中计算两个日期之间的天数

    在 Python 中处理日期和时间时 计算两个日期之间的天数是一项常见任务 无论您是构建预订系统 日程安排工具还是任何其他涉及日期和时间的应用程序 计算两个日期之间的天数都是一个关键功能 在本文中 我们将讨论如何在 Python 中计算两个
  • 什么是中间人 (MITM) 攻击?

    A 中间人 MITM 攻击是一种常见的网络安全威胁 如果处理不当 可能会造成严重后果 在这种类型的攻击中 恶意行为者会拦截 中继并可能改变认为彼此直接通信的两方之间的通信 本文将深入探讨 MITM 攻击带来的威胁 攻击者使用的技术以及个人和
  • 如何利用技术进步实现完美的远程办公

    远程工作并不是一个新趋势 作家 记者和艺术家总是有机会在舒适的家中工作 尽管如此 远程办公始终与技术密切相关 在过去 远程工作人员依赖邮件服务和交通 随着这两个领域变得越来越好 越来越多的人能够在家执行工作任务 然而 直到互联网的出现 这种
  • 如何在 Debian 9 上设置 Apache 虚拟主机

    在本教程中 我们将引导您了解如何在 Debian 9 上设置 Apache 虚拟主机 Apache 虚拟主机允许您在一台计算机上托管多个域 使用虚拟主机时 您可以为每个域或子域指定不同的文档根 包含网站文件的目录 创建单独的安全策略 使用不
  • 如何在 CentOS 8 上安装 R

    R 是一种开源编程语言和免费环境 专门从事统计计算和图形表示 它由 R 统计计算基金会支持 主要供统计学家和数据挖掘人员用于开发统计软件和执行数据分析 本文介绍如何在 CentOS 8 上安装 R 先决条件 在继续本教程之前 请确保您已满足
  • 如何更改 SFTP 端口

    SFTP SSH 文件传输协议 是一种安全文件协议 用于通过加密连接在两台主机之间传输文件 它还允许您对远程文件执行各种文件操作并恢复文件传输 SFTP 可用作旧版 FTP 协议的替代品 它具有 FTP 的所有功能 但连接更安全 本文介绍如
  • 如何在 Ubuntu 18.04 上设置或更改时区

    在 Ubuntu 上 系统的时区是在安装过程中设置的 但以后可以轻松更改 使用正确的时区对于许多与系统相关的任务和流程都很重要 例如 cron 守护进程使用系统的时区来执行 cron 作业 并且日志文件中的时间戳基于相同的时区 本教程演示如
  • 如何在 Debian 9 上安装 Yarn

    Yarn 是一个与 npm 兼容的 JavaScript 包管理器 它的创建是为了解决 npm 的一系列问题 例如通过并行操作加快软件包安装过程并减少与网络连接相关的错误 在本教程中 我们将指导您如何安装Yarn在 Debian 9 系统上
  • 如何在 Ubuntu 18.04 上安装 Django

    Django 是一个免费开源的高级 Python Web 框架 旨在帮助开发人员构建安全 可扩展和可维护的 Web 应用程序 有不同的方法来安装 Django 具体取决于您的需要 它可以在系统范围内安装 也可以使用 pip 安装在 Pyth
  • 如何在 Linux 中添加目录到 PATH

    当您在命令行上键入命令时 您基本上是在告诉 shell 运行具有给定名称的可执行文件 在Linux中 这些可执行程序就像ls find file和其他文件 通常位于系统上的几个不同目录中 存储在这些目录中的任何具有可执行权限的文件都可以从任
  • 如何在 CentOS 8 上设置或更改时区

    使用正确的时区对于许多与系统相关的任务和流程至关重要 例如 cron 守护进程使用系统的时区来执行 cron 作业 并且日志文件中的时间戳基于同一系统的时区 在 CentOS 上 系统的时区是在安装过程中设置的 但以后可以轻松更改 本文介绍
  • Python range() 函数

    蟒蛇rangetype 通过定义范围的起点和终点来生成整数序列 它通常与for循环迭代数字序列 range 在 Python 2 和 3 中的工作方式有所不同 在Python 2中 有两个函数可以让你生成整数序列 range and xra
  • Linux 中的正常运行时间命令

    在本教程中 我们将介绍uptime命令 顾名思义 uptime命令显示系统已经运行了多长时间 它还显示当前时间 登录用户数以及过去 1 5 和 15 分钟的系统负载平均值 如何使用正常运行时间命令 uptime 命令的语法如下 uptime
  • 如何在 CentOS 7 上使用 VSFTPD 设置 FTP 服务器

    FTP 文件传输协议 是一种标准的客户端 服务器网络协议 允许用户在远程网络之间传输文件 有多种可用于 Linux 的开源 FTP 服务器 最流行和最广泛使用的是PureFTPd ProFTPD and vsftpd 在本教程中 我们将在
  • Python while 循环

    循环是编程语言的基本概念之一 当您想要多次重复特定的代码块直到满足给定条件时 循环会很方便 Python中有两种基本的循环结构 for and while loops 本教程涵盖了以下基础知识whilePython 中的循环 我们还将向您展
  • NumPy loadtxt 教程(从文件加载数据)

    在之前的教程中 我们讨论过NumPy 数组 我们看到了它如何使读取 解析和对数字数据执行操作的过程变得轻而易举 在本教程中 我们将讨论 NumPy loadtxt 方法 该方法用于解析文本文件中的数据并将其存储在 n 维 NumPy 数组中
  • Linux Bash 脚本编写第 3 部分 – 参数和选项

    到目前为止 您已经了解了如何编写无需用户输入即可完成工作的 Linux bash 脚本 今天我们将继续我们的 Linux bash 脚本系列 如果您想了解我们在谈论什么 我建议您查看之前的帖子 Bash 脚本基础知识 Bash 脚本 For
  • Pythonnamedtuple(将元组提升到一个新的水平)

    在本教程中 我们将深入研究命名元组 它们是什么 如何创建和操作它们 以及何时使用它们 或不使用它们 命名元组是Python内置的一部分收藏模块 并且它们提供了一种将数据捆绑在一个名称下的便捷方法 它们是 Python 内置元组数据类型的子类