Python中的dict/set/tuple語(yǔ)法深入解析
前言
在 Python 的內(nèi)置容器中,dict、set、tuple 是三種最基礎(chǔ)也最常用的數(shù)據(jù)結(jié)構(gòu)。但對(duì)于許多學(xué)習(xí)者而言,它們的語(yǔ)法常常呈現(xiàn)一種“相似又沖突、熟悉卻怪異”的狀態(tài):
{}是空字典,不是空集合{1}是集合而不是字典(1)不是元組1,卻是元組- 空集合必須通過(guò)
set()創(chuàng)建 - tuple 的“核心”竟然是逗號(hào),而不是括號(hào)
這些現(xiàn)象并不是隨意設(shè)計(jì)的產(chǎn)物,而是語(yǔ)法解析需求、語(yǔ)言歷史選擇、舊代碼兼容性共同作用的結(jié)果。本文將從 歷史背景、解析機(jī)制、符號(hào)語(yǔ)義、設(shè)計(jì)理念 等多個(gè)角度,系統(tǒng)解釋這三類(lèi)結(jié)構(gòu)的語(yǔ)法設(shè)計(jì)邏輯。
1. 為什么 dict 和 set 都使用{}?
dict 是 {} 的“歷史所有者”
在 Python 的早期版本(Python 1.x),只有字典可以使用花括號(hào)表示:
{"a": 1, "b": 2}當(dāng)時(shí)并無(wú) set 類(lèi)型,因此
{}當(dāng)然被直接用作字典字面量。這意味著:{}與 dict 已深度綁定- 大量歷史代碼依賴(lài)
{} - 無(wú)法在不破壞兼容性的前提下更改
因此,當(dāng) set 在 Python 2.3 被加入語(yǔ)言規(guī)范時(shí),花括號(hào)
{}已無(wú)可能作為 set 的完整、自由的字面量語(yǔ)法。那為什么 {1} 可以成為一個(gè) set?
雖然 set 不能完全占用
{},但在特定語(yǔ)法場(chǎng)景下,它依然可以使用花括號(hào)表示非空集合:{1, 2, 3}理由非常直接:
- set 的字面量不包含冒號(hào)
: - dict 的字面量必須包含鍵值對(duì),如
{key: value}
因此這兩個(gè)結(jié)構(gòu)在語(yǔ)法上可區(qū)分:
表達(dá)形式 類(lèi)型 解析依據(jù) {key: value}dict 存在冒號(hào),確定鍵值映射 {element1, element2}set 無(wú)冒號(hào),解析為集合 特別是:
{1} # 可被 unambiguously 解析為 set- set 的字面量不包含冒號(hào)
{} 為什么不能表示空集合?
因?yàn)椋?/p>
{} -> 可能是空字典,也可能是空集合Python 選擇保留
{}為空字典,這不僅是兼容性的考慮,也是為了保持語(yǔ)法一致性。結(jié)果是:{} # dict set() # 空集合這種“不對(duì)稱(chēng)的語(yǔ)法”正是最典型的 Python 歷史性選擇之一。
2. 為什么(1)不是元組?括號(hào)到底承擔(dān)了什么職責(zé)?
Python 語(yǔ)法中括號(hào)的主要功能:表達(dá)式分組
在 Python 中,圓括號(hào)的最核心作用不是創(chuàng)建元組,而是:
對(duì)表達(dá)式做分組,使其按照括號(hào)內(nèi)部的優(yōu)先級(jí)優(yōu)先計(jì)算。
例如:
x = (1 + 2) * 3
你顯然不會(huì)認(rèn)為
(1 + 2)是一個(gè)元組。同樣地,下面的語(yǔ)句:
(1)
也被解釋為:
一個(gè)被括號(hào)包裹的表達(dá)式,表達(dá)式結(jié)果為 1
因此它的類(lèi)型永遠(yuǎn)是:
type((1)) # int
真實(shí)決定元組的不是括號(hào),而是逗號(hào)
元組字面量的核心是 逗號(hào)
,。括號(hào)只是輔助性的語(yǔ)法結(jié)構(gòu),用于讓逗號(hào)組合成一個(gè)整體表達(dá)式。例如:
(1,) # 元組 1, # 也是元組
其語(yǔ)法規(guī)則可以歸納為:
Python 通過(guò)逗號(hào)將多個(gè)表達(dá)式綁定為序列結(jié)構(gòu);括號(hào)只是用于維持表達(dá)式邊界的容器。
因此所有以下表達(dá)式都合法:
a = 1, 2 # tuple b = (1, 2) # tuple c = (1, 2,) # tuple d = (1,) # tuple e = 1, # tuple
但:
(1) # int
因?yàn)闆](méi)有逗號(hào)。
為什么要這樣設(shè)計(jì)?
原因包括:
- Python 需要一種簡(jiǎn)單語(yǔ)法表示“不可變序列”
- 括號(hào)已經(jīng)用于表達(dá)式分組,不能讓其過(guò)載造成歧義
- 使用逗號(hào)作為核心語(yǔ)義可以避免沖突,也簡(jiǎn)化解析器設(shè)計(jì)
- 歷史上 tuple 語(yǔ)法比許多現(xiàn)代語(yǔ)言還要早,屬于較早期的語(yǔ)法傳統(tǒng)
這導(dǎo)致了 tuple 表面看似奇特,但實(shí)際上具有極強(qiáng)的一致性與可解析性。
3. 為什么空 set 必須用set()?
因?yàn)椋?/p>
{}已經(jīng)被 dict 占用- set 無(wú)法重新奪回空字面量語(yǔ)法
- 語(yǔ)法解析必須保持單義性(unambiguous)
- 舊代碼兼容性必須保持
因此:
set() # 空集合的唯一創(chuàng)建方式
而非空集合可以使用部分字面量語(yǔ)法:
{1, 2, 3}
這也是 Python 中最少見(jiàn)但必須了解的“構(gòu)造器優(yōu)先語(yǔ)法”:空對(duì)象依賴(lài)構(gòu)造函數(shù),而非空對(duì)象使用字面量。
4. dict / set / tuple 的符號(hào)為何不統(tǒng)一?語(yǔ)義化設(shè)計(jì)原則解析
Python 的容器語(yǔ)法并非追求形式一致,而是遵循:
語(yǔ)法應(yīng)表達(dá)“結(jié)構(gòu)語(yǔ)義”,而不是容器類(lèi)型本身。
換言之,符號(hào)是用來(lái)表達(dá)數(shù)據(jù)結(jié)構(gòu)的本質(zhì)含義,而不是隨意選擇的符號(hào)裝飾。
具體來(lái)說(shuō):
| 數(shù)據(jù)結(jié)構(gòu)語(yǔ)義 | 使用符號(hào) | 理由 |
|---|---|---|
| 有序可變序列 | [] | 體現(xiàn)“順序序列”結(jié)構(gòu)(與 C 風(fēng)格數(shù)組類(lèi)似) |
| 有序不可變序列 | () | 作為表達(dá)式邊界,同時(shí)與逗號(hào)構(gòu)成元組 |
| 鍵值映射 | {key: value} | 以冒號(hào)表達(dá)鍵到值的映射關(guān)系 |
| 無(wú)重復(fù)集合 | {element,...} | 采用與數(shù)學(xué)集合相似的表示法(但不允許空字面量) |
這種語(yǔ)法設(shè)計(jì)體現(xiàn)了 Python 的核心理念:
- 類(lèi)型語(yǔ)義由內(nèi)容推斷,而非由符號(hào)決定
- 符號(hào)代表結(jié)構(gòu)意義(mapping、sequence、set-like)
- 兼容性?xún)?yōu)先
- 易讀性?xún)?yōu)先
- 語(yǔ)法規(guī)則盡量保持最小歧義
5. Python 官方與社區(qū)對(duì)這些語(yǔ)法“怪現(xiàn)象”的看法
Python 之父 Guido 在多次討論中都坦言,若能重新設(shè)計(jì)語(yǔ)言,有些符號(hào)可能會(huì)選擇不同的形式。但今天 Python 的狀況是:
- 擁有龐大的歷史代碼庫(kù)
- 大量項(xiàng)目依賴(lài)既有語(yǔ)法
- 更改基礎(chǔ)語(yǔ)法會(huì)導(dǎo)致嚴(yán)重破壞性影響
- 現(xiàn)有方案雖然有“怪現(xiàn)象”,但在語(yǔ)法解析和語(yǔ)義層面高度一致
因此,dict / set / tuple 之間的這些特殊語(yǔ)法差異將會(huì)長(zhǎng)期存在。
到此這篇關(guān)于Python中dict/set/tuple語(yǔ)法的文章就介紹到這了,更多相關(guān)Python中dict/set/tuple語(yǔ)法內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- python: 判斷tuple、list、dict是否為空的方法
- Python中內(nèi)置數(shù)據(jù)類(lèi)型list,tuple,dict,set的區(qū)別和用法
- 簡(jiǎn)單談?wù)凱ython中的元祖(Tuple)和字典(Dict)
- python的dict,set,list,tuple應(yīng)用詳解
- Python 實(shí)現(xiàn)list,tuple,str和dict之間的相互轉(zhuǎn)換
- Python中的defaultdict模塊和namedtuple模塊的簡(jiǎn)單入門(mén)指南
- Python?中的?list、tuple、set、dict的底層實(shí)現(xiàn)小結(jié)
- Python中的解包(tuple和dict的解包、*、**)的幾種使用方法
相關(guān)文章
matplotlib畫(huà)混淆矩陣與正確率曲線的實(shí)例代碼
混淆矩陣也稱(chēng)誤差矩陣,是表示精度評(píng)價(jià)的一種標(biāo)準(zhǔn)格式,下面這篇文章主要給大家介紹了關(guān)于matplotlib畫(huà)混淆矩陣與正確率曲線的相關(guān)資料,需要的朋友可以參考下2021-06-06
詳解Python實(shí)現(xiàn)字典合并的四種方法
這篇文章主要為大家詳細(xì)介紹了Python的合并字典的四種方法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來(lái)幫助2022-03-03
keras 回調(diào)函數(shù)Callbacks 斷點(diǎn)ModelCheckpoint教程
這篇文章主要介紹了keras 回調(diào)函數(shù)Callbacks 斷點(diǎn)ModelCheckpoint教程,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2020-06-06
matplotlib 曲線圖 和 折線圖 plt.plot()實(shí)例
這篇文章主要介紹了matplotlib 曲線圖 和 折線圖 plt.plot()實(shí)例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2020-04-04
python numpy創(chuàng)造圖像矩陣示例詳解
這篇文章主要為大家介紹了python numpy創(chuàng)造圖像矩陣示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-08-08
Python文件循環(huán)寫(xiě)入行時(shí)防止覆蓋的解決方法
今天小編就為大家分享一篇Python文件循環(huán)寫(xiě)入行時(shí)防止覆蓋的解決方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2018-11-11
解決python xlrd無(wú)法讀取excel文件的問(wèn)題
今天小編就為大家分享一篇解決python xlrd無(wú)法讀取excel文件的問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2018-12-12

