Python 具名元组——我不只是可不变列表
Posted FesonX
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Python 具名元组——我不只是可不变列表相关的知识,希望对你有一定的参考价值。
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)
用途
- 面向对象
在日常开发中, 往往离不开关系型数据库对象和缓存, 以往使用 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'
- 转化为(类)字典对象
日常开发中之所以会使用字典来保存缓存的内容, 很重要的原因是为了方便解析为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
欢迎关注公众号: 程序员的碎碎念
个人博客: feson.tech
以上是关于Python 具名元组——我不只是可不变列表的主要内容,如果未能解决你的问题,请参考以下文章