引言
在Python中,有時需要自定義簡單但是有名字的記錄類型,如果使用字典或普通元組,通常會顯得有點笨重。此時,namedtuple就成為了一個很好的選擇。namedtuple是Python標準庫collections中的一個函數,用於創建和實例化類似於元組的對象,但這些對象有名稱,可以像字典一樣通過名稱來訪問字段。namedtuple相當於一個輕量級的類定義器,它本質上是一個Python類,可以像其他類一樣繼承、實例化、序列化和擴展。
正文
一、namedtuple的使用方法
namedtuple的使用方法與普通元組非常相似。首先需要導入collections庫,然後使用namedtuple函數來定義一個命名元組。定義時需要提供兩個參數:元組名稱和元素名稱列表。下面是一個簡單的例子:
from collections import namedtuple #定義一個命名元組 Person = namedtuple("Person", ["name", "age"]) #使用命名元組 person = Person(name="Tom", age=18) print(person.name) # Tom
在上面的例子中,定義了一個Person命名元組,包含name和age兩個字段。在實例化時,使用關鍵字參數來指定字段的值,可以像普通元組一樣通過索引或名稱來訪問元素。但不同的是,通過名稱訪問元素時更直觀和安全。
二、namedtuple與普通元組的比較
在使用namedtuple之前,可以先看一下普通元組的缺陷。
- 元組和其它序列一樣是有序的。當元素需要賦予語義時,就需要藉助位置來訪問元素。這會降低程序的可讀性,並讓代碼更加脆弱(如果代碼依賴於元組中的位置,那麼當元組結構發生變化時,很容易出錯)。
- 在表達簡單的對象時,元組常常是有用的——如果需要將其作為函數的參數,並且只有少數幾個值是有意義的。但是,當元組變得更大,或者需要添加一些方法或屬性來擴展元組時,這時候使用類會更好。
- 元組是不可變的,因此如果想在元素被賦值後修改它們是不可能的。這樣如果需要在修改後返回相似但是不同的對象時,就需要使用其他的數據類型(如列表)來存儲數據。
- 在元組中添加、刪除或修改元素會非常困難。當元組項數變得非常龐大時,元組會變得笨重,在這種情況下,盡量使用更合適的數據結構。
三、namedtuple的高級用法
namedtuple本身是可以繼承的,這意味着其可以和其他的類一樣進行擴展,添加自己的方法和屬性:
from collections import namedtuple #定義一個命名元組 Animal = namedtuple("Animal", ["name", "age"]) #定義一個Cat類,並繼承Animal類 class Cat(Animal): def __str__(self): return "cat: {name}, {age}".format(name=self.name, age=self.age) cat = Cat(name="Tom", age=3) print(cat) # cat: Tom, 3
此外,namedtuple還支持各種繼承和多重繼承的方式,可以方便地與需要繼承的類和對象進行交互。
四、namedtuple的性能測試
對於一個類定義器來說,其性能是一個非常重要的因素,下面從創建、訪問和執行效率三個方面對namedtuple進行性能測試,和普通元組進行比較。
1.創建效率
使用timeit模塊測試一個10000000個元素的元組和namedtuple的創建效率:
from collections import namedtuple import timeit def test_normal_tuple(): t = tuple(range(10000000)) def test_named_tuple(): Person = namedtuple("Person", list(range(10000000))) tuple = Person(*range(10000000)) if __name__ == "__main__": normal_time = timeit.timeit("test_normal_tuple()", setup="from __main__ import test_normal_tuple", number=1000) named_time = timeit.timeit("test_named_tuple()", setup="from __main__ import test_named_tuple", number=1000) print("normal tuple :", normal_time) print("named tuple :", named_time)
得到結果如下:
normal tuple : 1.4164350395202637 named tuple : 8.236930131912231
可以看到,namedtuple創建的速度比普通元組慢,因為它需要額外的計算來生成所需要的類定義,但這種差異在實際應用中並不會影響太多。
2.訪問效率
使用timeit模塊測試一個10000000個元素的元組和namedtuple的訪問效率:
from collections import namedtuple import timeit Person = namedtuple("Person", list(range(10000000))) tuple = Person(*range(10000000)) def test_normal_tuple(): t = tuple(range(10000000)) for i in range(len(t)): a = t[i] def test_named_tuple(): for i in range(10000000): a = tuple[i] if __name__ == "__main__": normal_time = timeit.timeit("test_normal_tuple()", setup="from __main__ import test_normal_tuple", number=1000) named_time = timeit.timeit("test_named_tuple()", setup="from __main__ import test_named_tuple", number=1000) print("normal tuple :", normal_time) print("named tuple :", named_time)
得到結果如下:
normal tuple : 5.558712959289551 named tuple : 6.515319109916687
可以看到,namedtuple與元組在訪問效率上並無明顯區別。
3.執行效率
使用timeit模塊測試一個空操作的元組和namedtuple的執行效率:
from collections import namedtuple import timeit Person = namedtuple("Person", ["name", "age"]) tuple = Person(name="Tom", age=3) def test_normal_tuple(): pass def test_named_tuple(): pass if __name__ == "__main__": normal_time = timeit.timeit("test_normal_tuple()", setup="from __main__ import test_normal_tuple", number=1000) named_time = timeit.timeit("test_named_tuple()", setup="from __main__ import test_named_tuple", number=1000) print("normal tuple :", normal_time) print("named tuple :", named_time)
得到結果如下:
normal tuple : 0.0016641616821289062 named tuple : 0.0016469955444335938
可以看到,namedtuple與元組在執行效率上幾乎無差別。
結論
總體來說,namedtuple相比普通元組來說有更好的可讀性,同時它本身也具備擴展性和繼承性。儘管在創建方面不如普通元組快,但巨大的拓展性和易用性彌補了這一點缺陷。在實際項目中,使用namedtuple可以提高代碼的可讀性和可維護性,減少由於人為疏忽帶來的錯誤。
原創文章,作者:小藍,如若轉載,請註明出處:https://www.506064.com/zh-hant/n/219980.html