樹結構是一種抽象數據類型,在計算機科學領域有着非常廣泛的應用。一顆樹可以簡單的表示為根, 左子樹, 右子樹。 而左子樹和右子樹又可以有自己的子樹。這似乎是一種比較復雜的數據結構,那么真的能像我們在標題中所說的那樣,用一行Python代碼就可以實現嗎?
一行代碼實現?
由於樹形結構的外層和內層有着相似的結構,所以多可以用遞歸的方式定義樹。再利用Python中提供的defaultdict
,我們就可以很輕松地定義樹了,而且只有一行代碼。
from collections import defaultdict def tree(): return defaultdict(tree)
這個代碼分享自https://gist.github.com/hrldcpr/2012250。根據上面的代碼,一棵樹就是一個默認值也為樹的字典。
具體效果演示
這樣實現的樹有兩個奇妙之處,第一點是我們不需要創建節點,就可以直接引用它們。例如:
users = tree() users['codingpy']['username'] = 'earlgrey' users['python']['username'] = 'Guido van Rossum'
如果僅從常規字典的特性來看,上面的賦值操作是不成立的,因為我們必須事先聲明users['codingpy'] = {}
。但是我們利用的是collections
模塊中的defaultdict
類,如果某個鍵不存在時,它就會利用tree()
來為該鍵創建一個初始值,因為tree是提供給defaultdict
的default_factory
。根據文檔介紹,如果提供該參數,參數的值就傳給defaultdict
構造器作為第一個參數。
如果我們以json格式打印上面代碼的話(即通過print(json.dumps(users))
),我們會得到下面的結果:
{"codingpy": {"username": "earlgrey"}, "python": {"username": "Guido van Rossum"}}
第二點就是我們甚至不用進行上面那樣的賦值操作,只需要引用就可以創建一棵樹。例如:
categories = tree() categories['Programming Languages']['Python'] categories['Python']['Standard Library']['sys'] categories['Python']['Standard Library']['os']
如果我們接着運行print(json.dumps(categories))
,就會得到下面的結果:
{"Python": {"Standard Library": {"sys": {}, "os": {}}}, "Programming Languages": {"Python": {}}}
第二個奇妙之處,也被稱作Autovivification,該特性最早出現在Perl中,指的是在某個數組被引用時自動創建該數組。Python本身是不支持該特性的,但可以通過本文所述的defaultdict
模仿。