介紹
和元組 tuple 一樣,NamedTuple 也是不可變數(shù)據(jù)類型,創(chuàng)建之后就不能改變內(nèi)容。
如其名,和 tuple 的區(qū)別在于“Named”,即"命名"。NamedTuple 不像數(shù)組那樣使用下標(biāo)讀寫(xiě),反而和類相似,使用 .
來(lái)讀寫(xiě)。
基本語(yǔ)法
創(chuàng)建 NamedTuple 的函數(shù)定義
collections.namedtuple(typename, field_names, *, rename=False, defaults=None, module=None)
參數(shù)說(shuō)明:
-
typename
:新創(chuàng)建的類的名稱。 -
field_names
:字段名稱列表。必須是有效的 Python 變量名稱,且不能以下劃線開(kāi)頭。 -
rename
:是否自動(dòng)轉(zhuǎn)換無(wú)效字段名。 -
defaults
:字段默認(rèn)值列表。 -
module
:__module__
的值。
使用教程
創(chuàng)建
首先看看如何創(chuàng)建命名元組。以 Point
(代表二維坐標(biāo)中的一個(gè)點(diǎn))為例:
# 導(dǎo)包
from collections import namedtuple
# 創(chuàng)建普通元組
point = (22, 33)
print(point) # 輸出:(22, 33)
# 創(chuàng)建命名元組
Point = namedtuple('Point', 'x y')
point_A = Point(22, 33)
print(point_A) # 輸出:Point(x=22, y=33)
重點(diǎn)是這兩句話
Point = namedtuple('Point', 'x y')
point_A = Point(22, 33)
需要注意,namedtuple()
是用來(lái)創(chuàng)建類的,不是創(chuàng)建對(duì)象實(shí)例!
我們先用 namedtuple
創(chuàng)建了一個(gè)名為 Point
,有兩個(gè)字段 x
、y
的子類,然后將這個(gè)類賦給 Point
變量。
然后 Point(22, 33)
就是普通的 new 的語(yǔ)法。
類似于如下代碼:
class Point:
def __init__(self, x, y):
self.x = x
self.y = y
point_A = Point(22, 33)
創(chuàng)建命名元組對(duì)象時(shí),也可以使用位置參數(shù)
a = Point(1, 2)
b = Point(y=2, x=1)
a == b # >>> True
field_names
參數(shù)用來(lái)設(shè)置命名元組字段名,有三種風(fēng)格可以選擇。
下面幾種都是等價(jià)寫(xiě)法:
Point = namedtuple('Point', 'x y')
Point = namedtuple('Point', 'x,y')
Point = namedtuple('Point', ['x', 'y'])
# 下面都是合法代碼
# 中間允許存在任意空白字符
Point = namedtuple('Point', 'x, \t\t\t\n\n y')
Point = namedtuple('Point', 'x \t\t\t\n\n y')
# 元組也可以
Point = namedtuple('Point', ('x', 'y'))
# 事實(shí)上只要是可迭代都行
def fields():
yield 'x'
yield 'y'
Point = namedtuple('Point', fields())
使用
命名元組首先是一個(gè)元組,元組能怎么用,命名元組當(dāng)然也可以。
print(point_A[0])
print(point_A[1])
print(*point_A) # tuple unpack
# 輸出
"""
22
33
22 33
"""
然后是命名元組的特殊用法:
print(point_A.x)
print(point_A.y)
# 輸出
"""
22
33
"""
常用方法
namedtuple
創(chuàng)建的類還附贈(zèng)了一些實(shí)用方法:
Point._make(iterable) # 從某個(gè)序列創(chuàng)建命名元組
point._asdict() # 轉(zhuǎn)成字典
point._replace(**kargs) # 返回一個(gè)新元組,新元組里的指定字段被替換為指定值
point._fields # 列出字段名
point._field_defaults # 列出字段默認(rèn)值
設(shè)置默認(rèn)值
可以為命名元組的字段設(shè)置默認(rèn)值,只需要在創(chuàng)建類的時(shí)候傳入 defaults
參數(shù)即可。
# 四維向量
# 默認(rèn)值為 Vector4D(0, 0, 0, 0)
Vector4 = namedtuple('Vector4D', 'x y z w', defaults=(0, 0, 0, 0))
v1 = Vector4()
v2 = Vector4(1)
v3 = Vector4(1, 2, w=4)
print(v1)
print(v2)
print(v3)
# 輸出
"""
Vector4D(x=0, y=0, z=0, w=0)
Vector4D(x=1, y=0, z=0, w=0)
Vector4D(x=1, y=2, z=0, w=4)
"""
默認(rèn)值的數(shù)量可以小于字段數(shù),表示為右邊 n 個(gè)參數(shù)設(shè)置默認(rèn)值。
Foo = namedtuple('Foo', 'a b c d', defaults=(1, 2))
print(Foo(22, 33))
print(Foo())
# 輸出
"""
Foo(a=22, b=33, c=1, d=2)
Traceback (most recent call last):
File "D:\TempCodeFiles\named_tuple.py", line 6, in <module>
print(Foo())
TypeError: Foo.__new__() missing 2 required positional arguments: 'a' and 'b'
"""
更好的表示方式
namedtuple()
的寫(xiě)法既不直觀,也不優(yōu)雅。Python 3.5 新增了一種更好的寫(xiě)法:
# >= Python 3.5
from typing import NamedTuple
class PointA(NamedTuple):
x: int = 0
y: int = 0
# >= Python 2
from collections import namedtuple
PointB = namedtuple('PointB', 'x y', defaults=(0, 0))
print(PointA(2, 3) == PointB(2, 3)) # 輸出:True
繼承并擴(kuò)展 NamedTuple
namedtuple()
返回的是一個(gè)正常的類。既然它是一個(gè)類,當(dāng)然也可以被繼承。
創(chuàng)建一個(gè) Point
命名元組,增加一個(gè)方法,求兩點(diǎn)距離。
# >= Python 3.5
class Point(NamedTuple):
x: int = 0
y: int = 0
def distance(self, p) -> float:
return math.sqrt((self.x - p.x) ** 2 + (self.y - p.y) ** 2)
# >= Python 2
class Point(namedtuple('Point', 'x y', defaults=(0, 0))):
def distance(self, p) -> float:
return math.sqrt((self.x - p.x) ** 2 + (self.y - p.y) ** 2)
a = Point()
b = Point(3, 2)
print(a, b)
print(a.distance(b))
應(yīng)用
讀 csv 文件
以讀入一個(gè)儲(chǔ)存英語(yǔ)單詞的 csv 文件為例。
import csv
from collections import namedtuple
# 定義命名元組
# 按照 csv 列名來(lái)定義字段
Word = namedtuple('Word', 'word, type, chs_def, eng_ch, context, example')
file_path = r'C:\Users\ZhouXiaokang\Desktop\單詞 Vol 1 Ch 1 Ep 2.csv'
with open(file_path, 'r', encoding='utf-8') as f:
reader = csv.reader(f)
next(reader) # 跳過(guò)標(biāo)題行
for word in map(Word._make, reader):
print(f'{word.word} {word.type}. {word.chs_def} | 例:{word.context}')
輸出
chirp n&v. (鳥(niǎo)、昆蟲(chóng))啾啾叫,發(fā)唧唧聲 | 例:(*chirp* *chirp* *chirp*)
screech v. (車輛、汽車輪胎)發(fā)出刺耳聲 | 例:(*screech*)
Shiroko term. 白子 | 例:
mug v. 對(duì)…行兇搶劫 | 例:You didn't get mugged, did you?
faint v. 暈厥;暈倒 | 例:What's that? You fainted from hunger?
......
作為字典的代替品表示數(shù)據(jù)
相對(duì)于字典的優(yōu)勢(shì):
1.快、小
2..field
比 ['field']
更清晰
以下源碼摘自 baidupcs_py 庫(kù):
class PcsFile(NamedTuple):
"""
A Baidu PCS file
path: str # remote absolute path
is_dir: Optional[bool] = None
is_file: Optional[bool] = None
fs_id: Optional[int] = None # file id
size: Optional[int] = None
md5: Optional[str] = None
block_list: Optional[List[str]] = None # block md5 list
category: Optional[int] = None
user_id: Optional[int] = None
ctime: Optional[int] = None # server created time
mtime: Optional[int] = None # server modifed time
local_ctime: Optional[int] = None # local created time
local_mtime: Optional[int] = None # local modifed time
server_ctime: Optional[int] = None # server created time
server_mtime: Optional[int] = None # server modifed time
shared: Optional[bool] = None # this file is shared if True
"""
path: str # remote absolute path
is_dir: Optional[bool] = None
is_file: Optional[bool] = None
fs_id: Optional[int] = None # file id
size: Optional[int] = None
md5: Optional[str] = None
block_list: Optional[List[str]] = None # block md5 list
category: Optional[int] = None
user_id: Optional[int] = None
ctime: Optional[int] = None # server created time
mtime: Optional[int] = None # server modifed time
local_ctime: Optional[int] = None # local created time
local_mtime: Optional[int] = None # local modifed time
server_ctime: Optional[int] = None # server created time
server_mtime: Optional[int] = None # server modifed time
shared: Optional[bool] = None # this file is shared if True
rapid_upload_info: Optional[PcsRapidUploadInfo] = None
dl_link: Optional[str] = None
@staticmethod
def from_(info) -> "PcsFile":
return PcsFile(
path=info.get("path"),
is_dir=info.get("isdir") == 1,
is_file=info.get("isdir") == 0,
fs_id=info.get("fs_id"),
size=info.get("size"),
md5=info.get("md5"),
block_list=info.get("block_list"),
category=info.get("category"),
user_id=info.get("user_id"),
ctime=info.get("ctime"),
mtime=info.get("mtime"),
local_ctime=info.get("local_ctime"),
local_mtime=info.get("local_mtime"),
server_ctime=info.get("server_ctime"),
server_mtime=info.get("server_mtime"),
shared=info.get("shared"),
)
源碼
見(jiàn) Github。
關(guān)鍵部分在這里:文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-848081.html
# Build-up the class namespace dictionary
# and use type() to build the result class
# 收集類的方法、字段等
class_namespace = {
'__doc__': f'{typename}({arg_list})',
'__slots__': (),
'_fields': field_names,
'_field_defaults': field_defaults,
'__new__': __new__,
'_make': _make,
'__replace__': _replace,
'_replace': _replace,
'__repr__': __repr__,
'_asdict': _asdict,
'__getnewargs__': __getnewargs__,
'__match_args__': field_names,
}
for index, name in enumerate(field_names):
doc = _sys.intern(f'Alias for field number {index}')
class_namespace[name] = _tuplegetter(index, doc)
# 創(chuàng)建新類
result = type(typename, (tuple,), class_namespace)
type()
函數(shù)傳入一個(gè)參數(shù),用來(lái)獲取對(duì)象的類;如果傳入三個(gè)參數(shù),就變成了動(dòng)態(tài)創(chuàng)建類,相當(dāng)于 class
的動(dòng)態(tài)寫(xiě)法。文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-848081.html
class Foo:
def hello(self):
print('Hello')
# 等價(jià)于
def hello(self):
print('Hello')
Foo = type('Foo', (object,), {'hello': hello})
參考文章
- https://docs.python.org/zh-cn/3/library/collections.html#collections.namedtuple
- https://realpython.com/python-namedtuple/
到了這里,關(guān)于【Python 高級(jí)特性】深入 NamedTuple 命名元組的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!