python元组为什么不可变_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)

用途

面向对象

在日常开发中, 往往离不开关系型数据库对象和缓存, 以往使用 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

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值