collections模块_namedtuple

本文详细介绍了Python的collections.namedtuple模块,包括其参数说明、内存占用、使用示例、常用方法以及一些实用小技巧。namedtuple提供了一种创建轻量级类的方式,增强了tuple的可读性,并允许通过属性访问元素。文章还提到了typing.namedtuple的使用,以及如何自定义属性和方法的doc说明。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Author: 酱橙

参考文档:python.org

1. namedtuple

介绍:

collections.namedtuple方法是针对tuple类型数据的一个工厂方法,并且为tuple的每个值添加对应的字段,增强了 tuple 数据的可读性。并且,普通tuple对应的操作,namedtuple也可以执行,比如说tuple类型和 list类型的互相转化…等等。

推而广之,对于简单的类来说,可以通过 namedtuple 来直接生成。

具体可传入的参数:

collections.namedtuple(typename, field_names, *, 
                       rename=False, defaults=None, module=None)

1.1参数说明:

typename: 根据传入的 typename 返回一个对应名字的 tuple的子类(一般将typename的值和返回接收的变量名书写成一样的), 并且对该子类实例化之后,可以通过 __repr__()方法来查看实例对象的各个属性。

field_namerename参数:

  • 该字段接收的是一个序列,也可以接收一个通过逗号或者空格隔开的字符串:
    'x y'or'x, y'

  • 需要注意的是,filed_name 字段遵循 Python 标准的命名规范,并且不能是关键字。因此,如果filed_name字段可能会出现Python内部使用的关键字的话,最好设置 rename = True。此时对应的 filed_name 会被自动重命名。

    例如:['abc', 'def', 'ghi', 'abc']==> ['abc', '_1', 'ghi', '_3']

default参数:

  • 该参数的作用是给对应的变量添加默认值,传入的数据类型是一个序列,当然也可以不传,默认为None

  • 例如此时的file_name传入的参数为['x','y','z']defaults传入的参数为(1,2)
    因为默认参数得跟在普通形参的后面,因此时的 x默认值依旧为 0,y的默认值为1,z的默认值为2.

module 参数:

该类的 __module__值将会被赋值为 该参数传入的值,一般用不着。

1.2占用内存大小:

  1. 这种命名的元祖所占的空间并不比普通元祖占的空间更多(没有对应的per-instance dictionaries 😵),具体不太理解。

参见原文:

Named tuple instances do not have per-instance dictionaries, so they are lightweight and require no more memory than regular tuples.

  1. 所占的空间比 对应的字典要少很多:

测试:

import sys
import collections

a = {'name':"Tomsom",'age':12,'job':'Cooker'}
qwe = collections.namedtuple("MyTupleClass",['name','age','job'])
obj = qwe("Tomsom",12,'Cooker')
# ======
sys.getsizeof(a)		# 240
sys.getsizeof(obj)		# 72
sys.getsizeof(obj._asdict)   # 64

1.3 示例:

import collections
MyTupleClass = collections.namedtuple("MyTupleClass",
                                      ['name','age','job'])
obj = MyTupleClass("Tomsom",12,'Cooker')

上面通过 namedTuple创建了一个 obj 的对象

对于 CSV 文件或者是 数据取读取方面,namedtupled也有其妙用:

import csv
EmployeeRecord = namedtuple('EmployeeRecord', 
                           'name, age, title, department, paygrade')
# CSV:
for emp in map(EmployeeRecord._make, 
               csv.reader(open("employees.csv", "rb"))):
    print(emp.name, emp.title)
# SQL:
import sqlite3
conn = sqlite3.connect('/companydata')
cursor = conn.cursor()
cursor.execute('SELECT name, age, title, department, paygrade '
               'FROM employees')
for emp in map(EmployeeRecord._make, cursor.fetchall()):
    print(emp.name, emp.title)

1.4 常用的几个方法:(骚操作)

为了防止自带的方法与属性发生冲突的可能性,每个方法前面都有一个 单下划线,内置的共包含三个方法,两个属性:

classmethod somenamedtuple._make(iterable)

  • 将序列实例化为当前类的实例对象。
>>> t = [11, 22]
>>> Point._make(t)
Point(x=11, y=22)

somenamedtuple._asdict()

>>> p = Point(x=11, y=22)
>>> p._asdict()
{'x': 11, 'y': 22}
  • 把当前对象转化为一个字典【感觉可以用在反序列化上面】

  • 需要注意的是在python 3.7的时候,返回的是OrderedDict数据类型,在Python3.8的时候,返回的则是一个普通的dict数据类型。

somenamedtuple._replace(**kwargs)

  • 修改对应实例的参数,修改的时候会新开辟一个空间,因此需要赋值回原来的内存空间.

示例

>>> p = Point(x=11, y=22)
>>> p._replace(x=33)
Point(x=33, y=22)

for partnum, record in inventory.items():
	inventory[partnum] = record._replace(price=newprices[partnum], 
                                         timestamp=time.now())

somenamedtuple._fields

查看当前对象/类有哪些属性。这个操作可以结合 mixin的编程思想。

示例

>>> p._fields            # view the field names
('x', 'y')

>>> Color = namedtuple('Color', 'red green blue')
# 下面这一行将两个类的字段放在了一起
>>> Pixel = namedtuple('Pixel', Point._fields + Color._fields)
>>> Pixel(11, 22, 128, 255, 0)
Pixel(x=11, y=22, red=128, green=255, blue=0)

somenamedtuple._field_defaults

  • 查看具有默认值的参数,返回的是一个字典。
Account = namedtuple('Account', ['type', 'balance'], defaults=[0])
Account._field_defaults		# {'balance': 0}
Account('premium')			# Account(type='premium', balance=0)

1.5一些小技巧

1.5.1 获取属性的值

同样它也可以用 getattr()来获取变量的值。

>>> getattr(p, 'x')    # p 就是实例出来的对象
11

1.5.2 拆包实例化

当需要实例化一个对象的时候,可以通过字典拆包的方式把值传递进去。

>>> d = {'x': 11, 'y': 22}
>>> Point(**d)
Point(x=11, y=22)

1.5.3拆包获取属性值

>>> Point = namedtuple('Point', ['x', 'y'])
>>> p = Point(11, y=22) 
>>> p[0] + p[1]     # 像普通元组一样用索引获取值
33
>>> x, y = p        # 像普通元组一样进行拆包
>>> x, y
(11, 22)
>>> p.x + p.y       # 像类变量一样直接通过点语法获取值
33

1.5.4 创建子类:

因为 namedtupled 被认作一个Python的类,所以可以通过继承的方式来进行属性和方法的添加。下面的例子展示了 hypot 这个 property 属性和实例对象格式化的定义。

>>> class Point(namedtuple('Point', ['x', 'y'])):
    	# __slot__ 里面规定了实例字典里面包含的属性,
   		# 定义为空之后,实例对象的 __dict__ 即为空
        # 作用就是减少每个实例对象占用的内存空间
...     __slots__ = ()
...     @property
...     def hypot(self):
...         return (self.x ** 2 + self.y ** 2) ** 0.5
...     def __str__(self):
...         return 'Point: x=%6.3f  y=%6.3f  hypot=%6.3f' % (self.x, self.y, self.hypot)

>>> for p in Point(3, 4), Point(14, 5/7):
...     print(p)
Point: x= 3.000  y= 4.000  hypot= 5.000
Point: x=14.000  y= 0.714  hypot=14.018

Point: x= 3.000 y = 4.000 hypot = 5.000
Point: x=14.000 y = 0.714 hypot = 14.018

# 打印一下实例对象的 __dict__ 属性
Point(3,4).__dict__    # {}

通过上面的例子我们看到了如何通过一个 namedtuple 新建一个子类,

但是这种方式依旧比较麻烦,可以通过_fileds属性来进行更简化的操作:

Point3D = collections.namedtuple('Point3D', Point._fields + ('z',))

然后查看 Point3D 这个类里面包含的属性:

Point3D._fields    # ('x', 'y', 'z')

1.5.5 自定义属性及方法的doc说明

Point.__doc__ = 'Hardcover book in active collection'
Point3D.x.__doc__

然后查看一下对应属性的说明内容:

Point3D.x.__doc__		# '我是一个 x'

1.5.6 typing.namedtuple

typing模块中也有一个 **namedtuple **方法,然后它是这么用的:

class Employee(NamedTuple):
    name: str
    eid: int

看起来是不是很奇怪,但是它等价于下面这种写法

Employee = collections.namedtuple('Employee', ['name', 'id'])

也就是说,习惯于 class关键字的小伙伴有福音了,只要继承自NamedTuple,就可以调用 collections.namedtuple里面的方法,并且具有相同的特性。

当然,如果需要给name和 eid 属性添加默认值,如下:

class Employee(NamedTuple):
    name:str
    eid:int = 3
e2 = Employee('Guido')

查看一下 e2的值:

e2.eid     # 3

对于 NamedTuple来说,就可以不使用 _doc_ 这个方法来添加注释了,直接往类里面扔就完事…

class Employee(NamedTuple):
    """Represents an employee."""
    name: str
    id: int = 3

    def __repr__(self) -> str:
        return f'<Employee {self.name}, id={self.id}>'

说 明

当你使用NamedTuple,如果你需要查看类属性对应的变量类型的话,可以通过_filed_types来获取(注意:这是collections.namedtuple里面没有的):

e2 = Employee('Guido')
e2._field_types		# OrderedDict([('name', str), ('eid', int)])

但是在 Python 3.9 中,更推荐使用 __annotations__这个方法(more standard):

e2.__annotations__  # OrderedDict([('name', str), ('eid', int)])

最后感谢女朋友的支持
此刻如果能有一杯奶茶就更好了:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值