百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 编程字典 > 正文

Python的好工具namedtuple完整指南

toyiye 2024-07-09 22:55 13 浏览 0 评论

Python的ttuple

写一个最简单的tuple例子a是一个typle有三个元素,它的主要使用方式与listi没有太多的区别,主要的区别是tuple不能修改。


a = 1,2,3
print(type(a))
  • 元组tuple
  • 列表 ls =[]
  • 字典dc={}

这些知识可以看我之前写的文章或者网上搜索

namedtuple有名字的元组

Python 的 namedtuple() 是集合中可用的工厂函数。它允许您创建具有命名字段的子类。您可以使用点表示法和字段名称访问给定命名元组中的值,

为了提高代码的可读性,它提供了一种使用描述性字段名称而不是整数索引来访问值的方法,大多数时候,整数索引不会提供有关值的任何上下文。此功能还使代码更简洁、更易于维护。namedtuple

相比之下,将索引用于常规元组中的值可能会很烦人、难以阅读且容易出错。如果元组有很多字段。

正常情况的元组使用的是索引

a = 1,2,3
print(type(a))
print(a[0], a[1],a[2])
<class 'tuple'>
1 2 3

namedtuple与tuple的区别

它除了命名元组的这一主要特征外, :

  • 是不可变的数据结构
  • 具有一致的哈希值
  • 可以用作字典键
  • 可成套存取
  • 根据类型和字段名称提
  • 提供有用的字符串表示形式,以格式打印元组内容name=value
  • 支持索引
  • 提供其他方法和属性,例如 ._make()、_asdict()、._fields 等
  • 向后兼容常规元组
  • 具有与常规元组相似的内存消耗

实际上它的一个核心功能是对元素的存储可以通过key云获取,这一点有点像字典类型。

创建nametuple

>>> # Create a 2D point as a tuple
>>> point = (2, 4)
>>> point
(2, 4)

>>> # Access coordinate x
>>> point[0]
2
>>> # Access coordinate y
>>> point[1]
4

>>> # Try to update a coordinate value
>>> point[0] = 3
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: 'tuple' object does not support item assignment

可以看到point这个tuple是通过索引值取值,但是不能修改其中的元素。

像创建class一样创建namedtuple

>>> from collections import namedtuple

>>> # Create a namedtuple type, Point
>>> Point = namedtuple("Point", "x y")
>>> issubclass(Point, tuple)
True

>>> # Instantiate the new type
>>> point = Point(2, 4)
>>> point
Point(x=2, y=4)

>>> # Dot notation to access coordinates
>>> point.x
2
>>> point.y
4

>>> # Indexing to access coordinates
>>> point[0]
2
>>> point[1]
4

>>> # Named tuples are immutable
>>> point.x = 100
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: can't set attribute

Point = namedtuple("Point", "x y")中有两个属性x,y可以通过point.xpoint.y云取得这个数据。

print("=====namedtuple=====")
Point = namedtuple("Point", "x y")
print(Point.x)
print(Point)

point = Point(2, 4)
print(point)
print(point.x,point.y)
print(point[0],point[1],)
print("===========")
=====namedtuple=====
<_collections._tuplegetter object at 0x00000279F62F2D60>
<class '__main__.Point'>
Point(x=2, y=4)
2 4
2 4
===========

如果仔细观察可以发现

  • Point = namedtuple("Point", "x y")创建了一个类似于Point的class
  • 有两个属性x,y
  • point = Point(2, 4)些时创建了一个Point类型的实例point属性x,y分别赋值

如何获取这个typle的值:

  • 通过索引:print(point[0],point[1],)
  • 通过自定义索引 print(point.x,point.y)

最后得到的结果是一样的。但是元组的每个元有了对应的名字x,y 这样元素值都有了实际的含义。

namedtuple的嵌套赋值

>>> from collections import namedtuple

>>> Person = namedtuple("Person", "name children")
>>> john = Person("John Doe", ["Timmy", "Jimmy"])
>>> john
Person(name='John Doe', children=['Timmy', 'Jimmy'])
>>> id(john.children)
139695902374144

>>> john.children.append("Tina")
>>> john
Person(name='John Doe', children=['Timmy', 'Jimmy', 'Tina'])
>>> id(john.children)
139695902374144

>>> hash(john)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'list'
  • Person = namedtuple("Person", "name children")有两个属性name children
  • john = Person("John Doe", ["Timmy", "Jimmy"])分别给两个属性赋值其中children是一个列表
Person = namedtuple("Person", "name children")
john = Person("John Doe", ["Timmy", "Jimmy"])
print(john       )

print("======")
===========
Person(name='John Doe', children=['Timmy', 'Jimmy'])
======

实际上你仍然可以使用索引获取数据。

带有默认值的namedtuple

Developer = namedtuple( "Developer", 
                         "name level language", 
                          defaults=["Junior", "Python"]
    )

print(Developer("John"))
=====
Developer(name='John', level='Junior', language='Python')
=====

可以看到我们只是给 Developer设置了一个名字,其他的两个属性levellanguage使用的默认值

给namedtuple设置模块信息

>>> from collections import namedtuple

>>> Point = namedtuple("Point", "x y", module="custom")
>>> Point
<class 'custom.Point'>
>>> Point.__module__
'custom'
  • module="custom"
  • <class 'custom.Point'> 此时 Point变成custom模块下的一个类了

使用 _make函数创建namedtuple的一个对象实例

>>> from collections import namedtuple

>>> Person = namedtuple("Person", "name age height")
>>> Person._make(["Jane", 25, 1.75])
Person(name='Jane', age=25, height=1.75)

使用_asdict 函数把namedtuple转换成dict字典类型

>>> from collections import namedtuple

>>> Person = namedtuple("Person", "name age height")
>>> jane = Person("Jane", 25, 1.75)
>>> jane._asdict()
{'name': 'Jane', 'age': 25, 'height': 1.75}

使用_replace函数替换nmaetuple实例中的属性值

>>> from collections import namedtuple

>>> Person = namedtuple("Person", "name age height")
>>> jane = Person("Jane", 25, 1.75)

>>> # After Jane's birthday
>>> jane = jane._replace(age=26)
>>> jane
Person(name='Jane', age=26, height=1.75)

使用_fields来扩展namedtuple

>>> from collections import namedtuple

>>> Person = namedtuple("Person", "name age height")

>>> ExtendedPerson = namedtuple(
...     "ExtendedPerson",
...     [*Person._fields, "weight"]
... )

>>> jane = ExtendedPerson("Jane", 26, 1.75, 67)
>>> jane
ExtendedPerson(name='Jane', age=26, height=1.75, weight=67)
>>> jane.weight
67

可以看到Person中有三个属性,ExtendedPerson通过使用Person中的属性,动态 扩展一个 weight属性,这样ExtendedPerson具备了四个属性。这个功能有点像class面向对象编程中的继续,子类拥有父类的属性民。然而这两种实际上是不同的概念,只是表现形式上有点类似。

使用nametuple写更好的代码

可以比较以下两段程序的逻辑,发现使用namedtuple列好的表示出不同字字段的函数

>>> from collections import namedtuple

>>> Pen = namedtuple("Pen", "width style beveled")
>>> pen = Pen(2, "Solid", True)

>>> if pen.width == 2 and pen.style == "Solid" and pen.beveled:
...     print("Standard pen selected")
...
>>> pen = (2, "Solid", True)

>>> if pen[0] == 2 and pen[1] == "Solid" and pen[2]:
...     print("Standard pen selected")
...
Standard pen selected

使用namedtuple实现函数返回多个值

小知识: divmod函数

  • python divmod() 函数把除数和余数运算结果结合起来,
  • 返回一个包含商和余数的元组(a // b, a % b)
>>> from collections import namedtuple

>>> def custom_divmod(a, b):
...     DivMod = namedtuple("DivMod", "quotient remainder")
...     return DivMod(*divmod(a, b))
...

>>> custom_divmod(8, 4)

使用namedtuple减少函数的参数个数

User = namedtuple("User", "username client_name plan")
user = User("john", "John Doe", "Premium")

def create_user(db, user):
    db.add_user(user.username)
    db.complete_user_profile(
        user.username,
        user.client_name,
        user.plan
    )

使用namedtuple从文件数据库中读取数据

如下有一段CSV文件的数据模式

name,job,email
"Linda","Technical Lead","linda@example.com"
"Joe","Senior Web Developer","joe@example.com"
"Lara","Project Manager","lara@example.com"
"David","Data Analyst","david@example.com"
"Jane","Senior Python Developer","jane@example.com"
>>> import csv
>>> from collections import namedtuple

>>> with open("employees.csv", "r") as csv_file:
...     reader = csv.reader(csv_file)
...     Employee = namedtuple("Employee", next(reader), rename=True)
...     for row in reader:
...         employee = Employee(*row)
...         print(employee.name, employee.job, employee.email)
...
Linda Technical Lead linda@example.com
Joe Senior Web Developer joe@example.com
Lara Project Manager lara@example.com
David Data Analyst david@example.com
Jane Senior Python Developer jane@example.com

namedtuple是否能直接替换字典

两者看起来是一样的,但是字典可以直接使用,动态扩展,而namedtuple只是一个功能扩展,两者解决的问题是不一样的。


>>> from collections import namedtuple

>>> jane = {"name": "Jane", "age": 25, "height": 1.75}
>>> jane["age"]
25

>>> # Equivalent named tuple
>>> Person = namedtuple("Person", "name age height")
>>> jane = Person("Jane", 25, 1.75)
>>> jane.age
25
>>> from collections import namedtuple

>>> jane = {"name": "Jane", "age": 25, "height": 1.75}
>>> jane["age"] = 26
>>> jane["age"]
26
>>> jane["weight"] = 67
>>> jane
{'name': 'Jane', 'age': 26, 'height': 1.75, 'weight': 67}

>>> # Equivalent named tuple
>>> Person = namedtuple("Person", "name age height")
>>> jane = Person("Jane", 25, 1.75)

>>> jane.age = 26
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: can't set attribute

>>> jane.weight = 67
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'Person' object has no attribute 'weight

比较namedtuple和dict的性能

可以用下面的程序云测试一下两者的性能

# namedtuple_dict_time.py

from collections import namedtuple
from time import perf_counter

def average_time(structure, test_func):
    time_measurements = []
    for _ in range(1_000_000):
        start = perf_counter()
        test_func(structure)
        end = perf_counter()
        time_measurements.append(end - start)
    return sum(time_measurements) / len(time_measurements) * int(1e9)

def time_dict(dictionary):
    "x" in dictionary
    "missing_key" in dictionary
    2 in dictionary.values()
    "missing_value" in dictionary.values()
    dictionary["y"]

def time_namedtuple(named_tuple):
    "x" in named_tuple._fields
    "missing_field" in named_tuple._fields
    2 in named_tuple
    "missing_value" in named_tuple
    named_tuple.y

Point = namedtuple("Point", "x y z")
point = Point(x=1, y=2, z=3)

namedtuple_time = average_time(point, time_namedtuple)
dict_time = average_time(point._asdict(), time_dict)
gain = dict_time / namedtuple_time

print(f"namedtuple: {namedtuple_time:.2f} ns ({gain:.2f}x faster)")
print(f"dict:       {dict_time:.2f} ns") 

namedtuple与@dataclass

实际上这两者的表现形式其实非常的相似

>>> from dataclasses import astuple, dataclass

>>> @dataclass
... class Person:
...     name: str
...     age: int
...     height: float
...     weight: float
...     country: str = "Canada"
...     def __iter__(self):
...         return iter(astuple(self))
...

>>> for field in Person("Jane", 25, 1.75, 67):
...     print(field)
...
Jane
25
1.75
67
Canada

namedtuple与typing.NamedTuple

Python 3.5 引入了一个名为 typing 的临时模块来支持函数类型注释或类型提示。此模块提供 NamedTuple,它是 的类型化版本。使用 ,您可以创建带有类型提示的类。按照示例,您可以创建一个等效的类型化命名元组,如下所示:namedtupleNamedTuplenamedtuplePerson


>>> from typing import NamedTuple

>>> class Person(NamedTuple):
...     name: str
...     age: int
...     height: float
...     weight: float
...     country: str = "Canada"
...

>>> issubclass(Person, tuple)
True
>>> jane = Person("Jane", 25, 1.75, 67)
>>> jane.name
'Jane'
>>> jane.name = "Jane Doe"
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: can't set attribute

使用 ,您可以创建支持类型提示和通过点表示法进行属性访问的元组子类。由于生成的类是元组子类,因此它也是不可变的。NamedTuple

在上面的示例中需要注意的一个微妙细节是,子类看起来更类似于数据类,而不是命名元组。NamedTuple

通过继而的方式来使用namedtuple

定义一个类继承nametuple

>>> from collections import namedtuple
>>> from datetime import date

>>> BasePerson = namedtuple(
...     "BasePerson",
...     "name birthdate country",
...     defaults=["Canada"]
... )

>>> class Person(BasePerson):
...     """A namedtuple subclass to hold a person's data."""
...     __slots__ = ()
...     def __repr__(self):
...         return f"Name: {self.name}, age: {self.age} years old."
...     @property
...     def age(self):
...         return (date.today() - self.birthdate).days // 365
...

>>> Person.__doc__
"A namedtuple subclass to hold a person's data."

>>> jane = Person("Jane", date(1996, 3, 5))
>>> jane.age
25
>>> jane
Name: Jane, age: 25 years old.

总结namedtuple一个让元素有name的元组

  • 它是一个tuple类
  • 有点像字典
  • 有点像dataclass
  • 可以被继承

相关推荐

为何越来越多的编程语言使用JSON(为什么编程)

JSON是JavascriptObjectNotation的缩写,意思是Javascript对象表示法,是一种易于人类阅读和对编程友好的文本数据传递方法,是JavaScript语言规范定义的一个子...

何时在数据库中使用 JSON(数据库用json格式存储)

在本文中,您将了解何时应考虑将JSON数据类型添加到表中以及何时应避免使用它们。每天?分享?最新?软件?开发?,Devops,敏捷?,测试?以及?项目?管理?最新?,最热门?的?文章?,每天?花?...

MySQL 从零开始:05 数据类型(mysql数据类型有哪些,并举例)

前面的讲解中已经接触到了表的创建,表的创建是对字段的声明,比如:上述语句声明了字段的名称、类型、所占空间、默认值和是否可以为空等信息。其中的int、varchar、char和decimal都...

JSON对象花样进阶(json格式对象)

一、引言在现代Web开发中,JSON(JavaScriptObjectNotation)已经成为数据交换的标准格式。无论是从前端向后端发送数据,还是从后端接收数据,JSON都是不可或缺的一部分。...

深入理解 JSON 和 Form-data(json和formdata提交区别)

在讨论现代网络开发与API设计的语境下,理解客户端和服务器间如何有效且可靠地交换数据变得尤为关键。这里,特别值得关注的是两种主流数据格式:...

JSON 语法(json 语法 priority)

JSON语法是JavaScript语法的子集。JSON语法规则JSON语法是JavaScript对象表示法语法的子集。数据在名称/值对中数据由逗号分隔花括号保存对象方括号保存数组JS...

JSON语法详解(json的语法规则)

JSON语法规则JSON语法是JavaScript对象表示法语法的子集。数据在名称/值对中数据由逗号分隔大括号保存对象中括号保存数组注意:json的key是字符串,且必须是双引号,不能是单引号...

MySQL JSON数据类型操作(mysql的json)

概述mysql自5.7.8版本开始,就支持了json结构的数据存储和查询,这表明了mysql也在不断的学习和增加nosql数据库的有点。但mysql毕竟是关系型数据库,在处理json这种非结构化的数据...

JSON的数据模式(json数据格式示例)

像XML模式一样,JSON数据格式也有Schema,这是一个基于JSON格式的规范。JSON模式也以JSON格式编写。它用于验证JSON数据。JSON模式示例以下代码显示了基本的JSON模式。{"...

前端学习——JSON格式详解(后端json格式)

JSON(JavaScriptObjectNotation)是一种轻量级的数据交换格式。易于人阅读和编写。同时也易于机器解析和生成。它基于JavaScriptProgrammingLa...

什么是 JSON:详解 JSON 及其优势(什么叫json)

现在程序员还有谁不知道JSON吗?无论对于前端还是后端,JSON都是一种常见的数据格式。那么JSON到底是什么呢?JSON的定义...

PostgreSQL JSON 类型:处理结构化数据

PostgreSQL提供JSON类型,以存储结构化数据。JSON是一种开放的数据格式,可用于存储各种类型的值。什么是JSON类型?JSON类型表示JSON(JavaScriptO...

JavaScript:JSON、三种包装类(javascript 包)

JOSN:我们希望可以将一个对象在不同的语言中进行传递,以达到通信的目的,最佳方式就是将一个对象转换为字符串的形式JSON(JavaScriptObjectNotation)-JS的对象表示法...

Python数据分析 只要1分钟 教你玩转JSON 全程干货

Json简介:Json,全名JavaScriptObjectNotation,JSON(JavaScriptObjectNotation(记号、标记))是一种轻量级的数据交换格式。它基于J...

比较一下JSON与XML两种数据格式?(json和xml哪个好)

JSON(JavaScriptObjectNotation)和XML(eXtensibleMarkupLanguage)是在日常开发中比较常用的两种数据格式,它们主要的作用就是用来进行数据的传...

取消回复欢迎 发表评论:

请填写验证码