Python namedtuple使用详解

@author StormMa
@date 2017-06-12


生命不息,奋斗不止!

前言

Python的collections模块在基础数据类型的基础上,提供了几个额外的数据类型:namedtuple, defaultdict, deque, Counter, OrderedDict等,其中defaultdict和namedtuple是两个很实用的扩展类型。我一贯的风格就是学一个数据类型,就想去看看源码,虽然看不太懂,但是总比不看的强,之前java的集合源码阅读也是基于这样一个目的。今天就从使用和源码的角度来看一下namedtuple。

namedtuple是继承自tuple的子类。namedtuple创建一个和tuple类似的对象,而且对象拥有可访问的属性。

定义namedtuple

类的声明

1
2
3
4
5
6
7
8
9
10
11
class NamedTuple(tuple):
_fields = ... # type: Tuple[str, ...]
def __init__(self, typename: str, fields: Iterable[Tuple[str, Any]], *,
verbose: bool = ..., rename: bool = ..., module: Any = ...) -> None: ...
@classmethod
def _make(cls, iterable: Iterable[Any]) -> NamedTuple: ...
def _asdict(self) -> dict: ...
def _replace(self, **kwargs: Any) -> NamedTuple: ...

定义一个namedtuple的User类型

1
2
3
4
5
User = collections.namedtuple('User', ['age', 'name'])
或者
User = collections.namedtuple('User', 'age, name')
或者
User = collections.namedtuple('User', 'age name')

对应源码

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
28
29
def namedtuple(typename, field_names, verbose=False, rename=False):
"""Returns a new subclass of tuple with named fields.
>>> Point = namedtuple('Point', ['x', 'y'])
>>> Point.__doc__ # docstring for the new class
'Point(x, y)'
>>> p = Point(11, y=22) # instantiate with positional args or keywords
>>> p[0] + p[1] # indexable like a plain tuple
33
>>> x, y = p # unpack like a regular tuple
>>> x, y
(11, 22)
>>> p.x + p.y # fields also accessable by name
33
>>> d = p._asdict() # convert to a dictionary
>>> d['x']
11
>>> Point(**d) # convert from a dictionary
Point(x=11, y=22)
>>> p._replace(x=100) # _replace() is like str.replace() but targets named fields
Point(x=100, y=22)
"""
# Validate the field names. At the user's option, either generate an error
# message or automatically replace the field name with a valid name.
if isinstance(field_names, str):
field_names = field_names.replace(',', ' ').split()
field_names = list(map(str, field_names))

创建对象

1
2
3
4
5
user = User = (21, 'StormMa')
或者
user = User(age=21, name='StormMa')
或者
user = User._make([21, 'name'])

属性访问

1
2
3
4
5
# 年龄
user.age
# 姓名
user.name

转换成字典

1
2
3
4
5
user_dict = user._asdict()
# 访问
user_dict['name']
user_dict['age']

替换属性值

1
user2 = user._replace(age=20)