Python 具名元组——我不只是不可变列表

封面.jpg

Intro

很多 Python 入门资料会将元组 (tuple) 介绍为 "不可变列表", 因其具备可迭代和可切片的能力, 同时无法修改元组中的值而得名. 然而这只是元组的其中一个特性而已.

元组的本质

元组是对数据的一个记录, 每个位置记录了某个字段的值, 位置和字段信息赋予了这组数据的意义. 听起来很像数据库中的某条数据记录, 假如数据的元素不保持某个固定的位置, 你还认为这个数据是可用的吗?

具名元组 —— 元组特性的最有力体现

具名元组来自 Python 内置库 collections.nametupled 中, 可以用来构建带字段名的元组和一个相应的类

使用 nametupled 构建的类的实例所消耗的内存与元组是一致的, 因为字段名都被保存在对应的类里面.
—— 译自 Fluent Python

声明方式一

nametuple 构造函数的首个参数为类名, 第二个参数为字段名信息, 可以是以空格隔开的字符串, 也可以是字符串数组.

In [14]: from collections import namedtuple

In [15]: UserInfo = namedtuple('UserInfo', 'username passwor
    ...: d block vip')

In [16]: coding = UserInfo('coding', 'ShowMeTheCode', '0', '
    ...: 1')

In [17]: coding.password
Out[17]: 'ShowMeTheCode'

In [18]: coding[1]
Out[18]: 'ShowMeTheCode'

声明方式二

这种方式利用了很 Pythonic 的解包方式进行声明

In [19]: columns = ['name', 'city', 'email']

In [20]: Contact = namedtuple('Contact', columns)

In [21]: contact = ['coding', 'Dongguan', 'fesonx@foxmail.co
    ...: m']

In [22]: coding_contact = Contact(*contact)

In [23]: coding_contact.city
Out[23]: 'Dongguan'

可以用元组进行解包声明, 这里就充分利用了元组的位置信息:

In [40]:  contact_desciption = ('Contact', ['name', 'city', 'email', 'phone'])

In [41]: Contact = namedtuple(*contact_desciption)

用途

  1. 面向对象
    在日常开发中, 往往离不开关系型数据库对象和缓存, 以往使用 ORM 框架时, 受益于 ORM 面向对象的思想, 可以很方便的用 instance.field 方式访问对象属性, 但是转化到缓存时, 特别是类似 Redis 这类只保存字节的缓存, 就失去了对象这一概念.
    以往我们常常使用字典来"挽回"一点面向对象的思想, 但是如前文引用所示, 不保存字段名的具名元组实例要比字典占用的内存小, 并且在获取对象属性时要比字典方便多了, 面向对象的思想得到体现.
In [35]: coding_dict = {"name": "coding", "city": "Dongguan", "email": "fesonx@fox
    ...: mail.com"}

In [36]: coding_dict.get('name') # 字典
Out[36]: 'coding'

In [37]: coding_contact.name # 具名元组
Out[37]: 'coding'
  1. 转化为(类)字典对象
    日常开发中之所以会使用字典来保存缓存的内容, 很重要的原因是为了方便解析为 json 格式返回, 以往的 ORM 对象 (如 Flask-SQLALchemy) 如不引用外部框架, 一般也不具备转为键值的能力. 而具名字典正有这样的特性, 利用内置的 _asdict() 方法即可:
In [20]: Contact = namedtuple('Contact', columns)

In [21]: contact = ['coding', 'Dongguan', 'fesonx@foxmail.co
    ...: m']

In [22]: coding_contact = Contact(*contact)

In [26]: coding_contact._asdict()
Out[26]:
OrderedDict([('name', 'coding'),
             ('city', 'Dongguan'),
             ('email', 'fesonx@foxmail.com')])

In [27]: import json

In [28]: json.dumps(coding_contact._asdict())
Out[28]: '{"name": "coding", "city": "Dongguan", "email": "fesonx@foxmail.com"}'

字典可以使用 .keys() 方法来得到键名列表, 而具名元组可以使用 ._fields 属性获得一个字段元组, 用来判断前端传入的排序属性是否存在非常方便:

In [48]: Contact._fields
Out[48]: ('name', 'city', 'email', 'phone')

In [49]: 'city' in Contact._fields
Out[49]: True

欢迎关注公众号: 程序员的碎碎念

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

  • Swift1> Swift和OC的区别1.1> Swift没有地址/指针的概念1.2> 泛型1.3> 类型严谨 对...
    cosWriter阅读 11,709评论 1 32
  • 一. Java基础部分.................................................
    wy_sure阅读 4,048评论 0 11
  • 1.JVM 堆内存和非堆内存 堆和非堆内存按照官方的说法:“Java 虚拟机具有一个堆(Heap),堆是运行时数据...
    yanzhu728阅读 1,017评论 0 0
  • ORA-00001: 违反唯一约束条件 (.) 错误说明:当在唯一索引所对应的列上键入重复值时,会触发此异常。 O...
    我想起个好名字阅读 6,069评论 0 9
  • 昨夜,大雨滂沱,我躺在床上静听雨声,骤雨密集,铿锵有力,却也凌乱急切,想你。从窗外望去,夏雨气势磅礴,遮天蔽日的酣...
    华枝春满5339阅读 709评论 4 7

友情链接更多精彩内容