1、namedtuple
tuple是不可变序列,当你不希望外界可以随意的改变你的函数返回值的时候,不妨将你的返回值以tuple的形式返回,tuple还可以做为字典的key,这些都是tuple的独到之处,此外,由于存储的方式不同,相同元素的tuple 要比list更快,使用的内存更少。
tuple虽然有这么多优点,但是呢,在使用的时候,你不得不用下角标来访问它的元素,这样对于代码的可读性来说是一种折损。
namedtuple弥补了tuple的这一缺陷,使得你可以像使用对象属性那样去访问数据
2、示例
2.1 代码
# coding=utf-8
from collections import namedtuple
Book = namedtuple('Book', ['name', 'price', 'count'])
book1 = Book(name='python', price=100.0, count=10)
print book1
print book1.name
print book1.price
print book1.count
2.2 如何创建
在上面的这段代码中,首先定义了一个namedtuple,第一个参数指定了它的类型,第二个参数则指定了字段名称,第二个参数除了写成list的形式,还可以写成字符串的形式,以空格分割,例如
Book = namedtuple('Book', 'name price count')
2.3 属性不可改变
如果你试图改变book1对象的某个属性,程序会直接报错的,因为它是一个特殊的tuple
2.4 更便捷的赋值过程
对于上面代码中的属性赋值过程,你可能会感到有些为难,因为如果字段特别多,那么一个一个的写代码去赋值就变得非常繁琐,如果你手里拥有的数据是一个字典,那么还可以这样去创始化它
book_dict = {
'name': 'c++',
'price': 99,
'count': 10
}
book2 = Book(**book_dict)
print book2
3、 namedtuple究竟是什么
不妨先打印一下Book
print Book
得到的结果是
这说明, namedtuple('Book', 'name price count') 返回的是一个类,Book恰好是我们传入的第一个参数,你可以将第一个参数修改成其他单词,然后再打印观察效果就会明白,第一个参数定义的是类的名字
深入namedtuple 的实现一探究竟
在 collections.py 文件中的293行开始,是对namedtuple的定义,注意看 356行的 class_definition 和 374 行的 exec class_definition in namespace
356行都是对属性的处理,356行,将这些数据整合成一个字符串,374行则对这个字符串进行了执行,或者说编译,得到的就是一个类
那么这个类又是如何生成的呢?
293行定义了类的模板
_class_template = '''\
class {typename}(tuple):
'{typename}({arg_list})'
__slots__ = ()
_fields = {field_names!r}
def __new__(_cls, {arg_list}):
'Create new instance of {typename}({arg_list})'
return _tuple.__new__(_cls, ({arg_list}))
@classmethod
def _make(cls, iterable, new=tuple.__new__, len=len):
'Make a new {typename} object from a sequence or iterable'
result = new(cls, iterable)
if len(result) != {num_fields:d}:
raise TypeError('Expected {num_fields:d} arguments, got %d' % len(result))
return result
def __repr__(self):
'Return a nicely formatted representation string'
return '{typename}({repr_fmt})' % self
def _asdict(self):
'Return a new OrderedDict which maps field names to their values'
return OrderedDict(zip(self._fields, self))
def _replace(_self, **kwds):
'Return a new {typename} object replacing specified fields with new values'
result = _self._make(map(kwds.pop, {field_names!r}, _self))
if kwds:
raise ValueError('Got unexpected field names: %r' % kwds.keys())
return result
def __getnewargs__(self):
'Return self as a plain tuple. Used by copy and pickle.'
return tuple(self)
__dict__ = _property(_asdict)
def __getstate__(self):
'Exclude the OrderedDict from pickling'
pass
{field_defs}
'''
这正是奥妙所在,nametuple根据我们传入的两个参数,格式化了这段字符串,然后exec 这段字符串,就生成了一个类,这个类继承了tuple,而后,我们用这个类创建对象