Python namedtuple
最后修改于 2024 年 1 月 29 日
Python namedtuple 教程介绍了如何在 Python 中使用 namedtuple。
Python namedtuple
Python namedtuple 是一种不可变的容器类型,其值可以通过索引和命名属性进行访问。它具有类似元组的功能,并增加了额外特性。命名元组是通过 `collections.namedtuple` 工厂函数创建的。
命名元组本质上是易于创建、不可变、轻量级的对象类型。命名元组可以使代码更整洁、更符合 Python 风格。它们类似于其他语言中的记录(C#、Java)。
Python namedtuple 基本示例
以下是一个使用命名元组的简单示例。
#!/usr/bin/python
from collections import namedtuple
City = namedtuple('City' , 'name population')
c1 = City('Bratislava', 432000)
c2 = City('Budapest', 1759000)
print(c1)
print(c2)
该示例创建了 city 命名元组。
from collections import namedtuple
首先,我们从 `collections` 模块导入 `namedtuple` 类型。
City = namedtuple('City' , 'name population')
我们定义了命名元组。第一个参数是命名元组的名称。第二个参数是字段名。字段名可以指定为字符串 `'name population'` 或列表 `['name', 'population']`。
c1 = City('Bratislava', 432000)
c2 = City('Budapest', 1759000)
这里我们创建了两个命名元组对象。
$ ./basic.py City(name='Bratislava', population=432000) City(name='Budapest', population=1759000)
Python namedtuple 访问
命名元组可以通过索引和其命名属性进行访问。
#!/usr/bin/python
from collections import namedtuple
City = namedtuple('City' , 'name population')
c1 = City('Bratislava', 432000)
c2 = City('Budapest', 1759000)
print(c1[0])
print(c1[1])
print(c2.name)
print(c2.population)
在示例中,我们演示了这两种方式。
$ ./accessing.py Bratislava 432000 Budapest 1759000
Python namedtuple 解包
解包是将可迭代元素存储到变量或函数参数中。
#!/usr/bin/python
from collections import namedtuple
City = namedtuple('City' , 'name population')
c1 = City('Bratislava', 432000)
c2 = City('Budapest', 1759000)
name, population = c1
print(f'{name}: {population}')
print('----------------------')
print(c2)
print(*c2, sep=': ')
在示例中,我们解包了我们的命名元组。
name, population = c1
这里我们将 `c1` 命名元组解包到两个变量中。
print(*c2, sep=': ')
这里我们使用 `*` 操作符将 `c2` 命名元组解包到 `print` 函数的参数中,这些参数将与给定的分隔符连接起来形成最终输出。
$ ./unpacking.py Bratislava: 432000 ---------------------- City(name='Budapest', population=1759000) Budapest: 1759000
#!/usr/bin/python
from collections import namedtuple
City = namedtuple('City' , 'name population')
d = { 'name': 'Bratislava', 'population': 432000}
c = City(**d)
print(c)
使用 `**` 操作符,我们可以将字典解包为命名元组的参数。
Python namedtuple 继承
由于命名元组是建立在普通类之上的,我们可以为它们添加功能。
#!/usr/bin/python
from collections import namedtuple
from math import sqrt
class Point(namedtuple('Point', 'x y')):
__slots__ = ()
@property
def hypot(self):
return sqrt((self.x ** 2 + self.y ** 2))
def __str__(self):
return f'Point: x={self.x} y={self.y} hypot={self.hypot}'
p = Point(5, 5)
print(p.hypot)
print(p)
我们有一个 `Point` 命名元组。我们向其中添加了 `hypot` 属性。
$ ./subclassing.py 7.0710678118654755 Point: x=5 y=5 hypot=7.0710678118654755
Python typing.NamedTuple
从 Python 3.6 开始,我们可以使用 `typing.NamedTuple` 来创建命名元组。
#!/usr/bin/python
from typing import NamedTuple
class City(NamedTuple):
name: str
population: int
c1 = City('Bratislava', 432000)
c2 = City('Budapest', 1759000)
print(c1)
print(c2)
在示例中,我们有一个继承自 `typing.NamedTuple` 的 City 类。属性带有类型提示。
Python namedtuple 默认值
可以使用 `defaults` 参数为字段提供默认值。
#!/usr/bin/python
from collections import namedtuple
from math import sqrt
class Point(namedtuple('Point', 'x y', defaults=[1, 1])):
__slots__ = ()
@property
def hypot(self):
return sqrt((self.x ** 2 + self.y ** 2))
def __str__(self):
return f'Point: x={self.x} y={self.y} hypot={self.hypot}'
p1 = Point(5, 5)
print(p1)
p2 = Point()
print(p2)
x 和 y 的默认值为 1。
$ ./defaults.py Point: x=5 y=5 hypot=7.0710678118654755 Point: x=1 y=1 hypot=1.4142135623730951
Python namedtuple 辅助函数
Python 为命名元组提供了一些辅助方法。
#!/usr/bin/python
from typing import NamedTuple
class Point(NamedTuple):
x: int = 1
y: int = 1
p = Point(5, 5)
print(p._fields)
print(p._field_defaults)
print(p._asdict())
`_fields` 是一个包含字段名字符串的元组。`_field_defaults` 是一个将字段名映射到默认值的字典。`_asdict` 方法返回一个新的有序字典,它将字段名映射到它们对应的值。
$ ./helpers.py
('x', 'y')
{'x': 1, 'y': 1}
OrderedDict([('x', 5), ('y', 5)])
Python namedtuple - 序列化为 JSON
可以使用 `_asdict` 方法将命名元组序列化为 JSON 格式。
#!/usr/bin/python
from typing import NamedTuple
import json
class City(NamedTuple):
name: str
population: int
c1 = City('Bratislava', 432000)
c2 = City('Budapest', 1759000)
c3 = City('Prague', 1280000)
c4 = City('Warsaw', 1748000)
cities = [c1, c2, c3, c4]
print(json.dumps(c1._asdict()))
json_string = json.dumps([city._asdict() for city in cities])
print(json_string)
借助 `json.dumps` 方法,我们序列化了一个城市和一系列城市。
$ ./json_output.py
{"name": "Bratislava", "population": 432000}
[{"name": "Bratislava", "population": 432000}, {"name": "Budapest", "population": 1759000},
{"name": "Prague", "population": 1280000}, {"name": "Warsaw", "population": 1748000}]
Python namedtuple 排序
在下面的示例中,我们对一个命名元组列表进行排序。
#!/usr/bin/python
from typing import NamedTuple
class City(NamedTuple):
id: int
name: str
population: int
c1 = City(1, 'Bratislava', 432000)
c2 = City(2, 'Budapest', 1759000)
c3 = City(3, 'Prague', 1280000)
c4 = City(4, 'Warsaw', 1748000)
c5 = City(5, 'Los Angeles', 3971000)
c6 = City(6, 'Edinburgh', 464000)
c7 = City(7, 'Berlin', 3671000)
cities = [c1, c2, c3, c4, c5, c6, c7]
cities.sort(key=lambda e: e.name)
for city in cities:
print(city)
借助 `sort` 方法和 lambda 函数,我们按名称对城市进行排序。
$ ./sorting.py City(id=7, name='Berlin', population=3671000) City(id=1, name='Bratislava', population=432000) City(id=2, name='Budapest', population=1759000) City(id=6, name='Edinburgh', population=464000) City(id=5, name='Los Angeles', population=3971000) City(id=3, name='Prague', population=1280000) City(id=4, name='Warsaw', population=1748000)
城市按名称升序排序。
Python namedtuple _make 辅助函数
`_make` 方法可以从现有的序列或可迭代对象创建一个新的命名元组实例。
#!/usr/bin/python
from collections import namedtuple
City = namedtuple('City' , 'name population')
c1 = City._make(('Bratislava', 432000))
c2 = City._make(('Budapest', 1759000))
print(c1)
print(c2)
该示例借助 `_make` 方法从元组创建了 City 命名元组。
Python namedtuple - 读取 CSV 数据
Python 命名元组在读取 CSV 数据时非常有用。
Bratislava, 432000 Budapest, 1759000 Prague, 1280000 Warsaw, 1748000 Los Angeles, 3971000 New York, 8550000 Edinburgh, 464000 Berlin, 3671000
我们有这个 CSV 文件。
#!/usr/bin/python
from collections import namedtuple
import csv
City = namedtuple('City' , 'name population')
f = open('cities.csv', 'r')
with f:
reader = csv.reader(f)
for city in map(City._make, reader):
print(city)
我们使用 `map` 和 `_make` 函数来创建简洁的代码。
$ ./read_csv.py City(name='Bratislava', population=' 432000') City(name='Budapest', population=' 1759000') City(name='Prague', population=' 1280000') City(name='Warsaw', population=' 1748000') City(name='Los Angeles', population=' 3971000') City(name='New York', population=' 8550000') City(name='Edinburgh', population=' 464000') City(name='Berlin', population=' 3671000')
Python namedtuple - 读取 SQLite 数据库
在下面的示例中,我们使用命名元组从 SQLite 数据库读取数据。
DROP TABLE IF EXISTS cities;
CREATE TABLE cities(id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT,
population INTEGER);
INSERT INTO cities(name, population) VALUES('Bratislava', 432000);
INSERT INTO cities(name, population) VALUES('Budapest', 1759000);
INSERT INTO cities(name, population) VALUES('Prague', 1280000);
INSERT INTO cities(name, population) VALUES('Warsaw', 1748000);
INSERT INTO cities(name, population) VALUES('Los Angeles', 3971000);
INSERT INTO cities(name, population) VALUES('New York', 8550000);
INSERT INTO cities(name, population) VALUES('Edinburgh', 464000);
INSERT INTO cities(name, population) VALUES('Berlin', 3671000);
这些是创建 `cities` 表的 SQL 语句。
$ sqlite3 ydb.db SQLite version 3.31.1 2020-01-27 19:55:54 Enter ".help" for usage hints. sqlite> .read cities.sql
我们使用 `sqlite3` 命令行工具生成 SQLite 数据库和 `cities` 表。
#!/usr/bin/python
from typing import NamedTuple
import sqlite3 as sqlite
class City(NamedTuple):
id: int
name: str
population: int
con = sqlite.connect('ydb.db')
with con:
cur = con.cursor()
cur.execute('SELECT * FROM cities')
for city in map(City._make, cur.fetchall()):
print(city)
我们读取 `cities` 表中的所有数据,并将每一行表转换为 `City` 命名元组。
来源
在本文中,我们学习了 Python namedtuple。
作者
列出所有 Python 教程。