python中的 NamedTuple与namedtuple

首先要知道的是python3中有typing模块含有类NamedTuple,collections模块含有函数namedtuple(该函数返回一个tuple的子类),这是官方文档传送门。

collections.namedtuple

namedtuple将创建一个和tuple类似的object,其中的元素可通过属性名访问,也可通过像tuple一样的下标来访问。其好处是通过名称访问数据能够让我们的代码更加的直观、规范,

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
from collections import namedtuple
 
# 定义一个namedtuple类型User,并包含name,sex和age属性。
User = namedtuple('User', ['name', 'sex', 'age'])
 
# 创建一个User对象
user = User(name='kongxx', sex='male', age=21)
 
# 也可以通过一个list来创建一个User对象,这里注意需要使用"_make"方法
user = User._make(['kongxx', 'male', 21])
 
print(user)
# User(name='user', sex='male', age=21)
 
# 获取用户的属性
print(user.name)
print(user.sex)
print(user.age)
 
# 修改对象属性,注意要使用"_replace"方法
user = user._replace(age=22)
print(user)
# User(name='user', sex='male', age=22)
 
# 将User对象转换成字典,注意要使用"_asdict"
print(user._asdict())
# OrderedDict([('name', 'kongxx'), ('sex', 'male'), ('age', 22)])

在python中,传统的tuple类似于数组,只能通过下标来访问各个元素,我们还需要注释每个下标代表什么数据。通过使用namedtuple,每个元素有了自己的名字,类似于C语言中的struct,这样数据的意义就可以一目了然了。当然,声明namedtuple是非常简单方便的。
代码示例如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
from collections import namedtuple
 
Friend=namedtuple("Friend",['name','age','email'])
 
f1=Friend('xiaowang',33,'[email protected]')
print(f1)
print(f1.age)
print(f1.email)
f2=Friend(name='xiaozhang',email='[email protected]',age=30)
print(f2)
 
name,age,email=f2
print(name,age,email)

类似于tuple,它的属性也是不可变的:

1
2
3
4
>>> big_yellow.age += 1
Traceback (most recent call last):
 File "<stdin>", line 1, in <module>
AttributeError: can't set attribute

能够方便的转换成OrderedDict:

1
2
>>> big_yellow._asdict()
OrderedDict([('name', 'big_yellow'), ('age', 3), ('type', 'dog')])

方法返回多个值的时候,其实更好的是返回namedtuple的结果,这样程序的逻辑会更加的清晰和好维护:

1
2
3
4
5
6
7
8
>>> from collections import namedtuple
>>> def get_name():
...   name = namedtuple("name", ["first", "middle", "last"])
...   return name("John", "You know nothing", "Snow")
...
>>> name = get_name()
>>> print name.first, name.middle, name.last
John You know nothing Snow

typing.NamedTuple

官方文档中认为下面这两段代码是等价的:

1
2
3
class Employee(NamedTuple):
    name: str
    id: int
1
Employee = collections.namedtuple('Employee', ['name', 'id'])

NamedTuple几乎等同于namedtuple,但NamedTuple拥有一个额外的属性__annotations__,该属性是一个将名字映射到字段类型的dict
值得注意 的是:继承自NamedTuple的类将是tuple的子类,但不会是NamedTuple的子类:
而其实例将像往常一样成为元组的实例,且不是NamedTuple的实例:

1
2
3
4
5
6
7
8
>>> class Employee(NamedTuple):
...     name: str
...     id: int
...    
>>> issubclass(Employee, NamedTuple)
False
>>> isinstance(Employee(name='guido', id=1), NamedTuple)
False

如果想了解为何如此,请参看下方参考中的第二个链接。

参考自:
https://blog.csdn.net/qq_39173907/article/details/80023694
http://www.cocoachina.com/articles/46911