首頁  >  文章  >  後端開發  >  Python資料結構:一個被低估的Namedtuple(二)

Python資料結構:一個被低估的Namedtuple(二)

coldplay.xixi
coldplay.xixi轉載
2020-10-20 17:10:303342瀏覽

python影片教學專欄繼續帶大家了解Python資料結構的Namedtuple。

Python資料結構:一個被低估的Namedtuple(二)

上篇Python資料結構:一個被低估的Namedtuple(一)講了namedtuple的一些基本用法,這篇繼續。

namedtuples和資料類別(Data Class)之間有什麼差別?

功能

在Python 3.7之前,可使用下列任一方法建立一個簡單的資料容器:

  • namedtuple
  • 常規類別
  • 第三方函式庫,attrs

如果您想使用常規類,那意味著您將必須實作幾個方法。例如,常規類別將需要一種__init__方法來在類別實例化期間設定屬性。如果您希望該類別是可雜湊的,則表示自己實作一個__hash__方法。為了比較不同的對象,還需要__eq__實作一個方法。最後,為了簡化偵錯,您需要一種__repr__方法。

讓我們使用常規類別來實作下我們的顏色用例。

class Color:
    """A regular class that represents a color."""

    def __init__(self, r, g, b, alpha=0.0):
        self.r = r
        self.g = g
        self.b = b
        self.alpha = alpha    def __hash__(self):
        return hash((self.r, self.g, self.b, self.alpha))    def __repr__(self):
        return "{0}({1}, {2}, {3}, {4})".format(
            self.__class__.__name__, self.r, self.g, self.b, self.alpha
        )    def __eq__(self, other):
        if not isinstance(other, Color):            return False
        return (
            self.r == other.r            and self.g == other.g            and self.b == other.b            and self.alpha == other.alpha
        )复制代码

如上,你需要實作好多方法。您只需要一個容器來為您保存數據,而不必擔心分散注意力的細節。同樣,人們偏好實作類別的一個關鍵區別是常規類別是可變的。

實際上,引入資料類別(Data Class)的PEP將它們稱為「具有預設值的可變namedtuple」(譯者註:Data Class python 3.7引入,參考: docs.python.org/zh-cn/3/lib…

現在,讓我們看看如何用資料類別來實作。

from dataclasses import dataclass
...@dataclassclass Color:
    """A regular class that represents a color."""
    r: float
    g: float
    b: float
    alpha: float复制代码

哇!就是這麼簡單。由於沒有__init__,您只需在docstring後面定義屬性即可。此外,必須使用類型提示對其進行註釋。

除了可變之外,資料類別還可以開箱即用提供可選字段。假設我們的Color類別不需要alpha字段。然後我們可以設定為可選。

from dataclasses import dataclassfrom typing import Optional
...@dataclassclass Color:
    """A regular class that represents a color."""
    r: float
    g: float
    b: float
    alpha: Optional[float]复制代码

我們可以像這樣實例化它:

>>> blue = Color(r=0, g=0, b=255)复制代码

由於它們是可變的,因此我們可以更改所需的任何字段。我們可以像這樣實例化它:

>>> blue = Color(r=0, g=0, b=255)
>>> blue.r = 1
>>> # 可以设置更多的属性字段
>>> blue.e = 10复制代码

相比之下,namedtuple預設情況下沒有可選字段。要添加它們,我們需要一點技巧和一些元編程。

提示:要添加__hash__方法,您需要通過將設置unsafe_hash為使其不可變True

@dataclass(unsafe_hash=True)class Color:
    ...复制代码

另一個區別是,拆箱(unpacking)是namedtuples的自帶的功能(first-class citizen)。如果希望資料類別具有相同的行為,則必須實現自己。

from dataclasses import dataclass, astuple
...@dataclassclass Color:
    """A regular class that represents a color."""
    r: float
    g: float
    b: float
    alpha: float    def __iter__(self):
        yield from dataclasses.astuple(self)复制代码

效能比較

僅比較功能是不夠的,namedtuple和資料類別在效能上也有所不同。資料類別基於純Python實作dict。這使得它們在訪問字段時更快。另一方面,namedtuples只是常規的擴展tuple。這意味著它們的實現基於更快的C代碼並具有較小的內存佔用量。

為了證明這一點,請考慮在Python 3.8.5上進行此實驗。

In [6]: import sys

In [7]: ColorTuple = namedtuple("Color", "r g b alpha")

In [8]: @dataclass
   ...: class ColorClass:
   ...:     """A regular class that represents a color."""
   ...:     r: float
   ...:     g: float
   ...:     b: float
   ...:     alpha: float
   ...: 

In [9]: color_tup = ColorTuple(r=50, g=205, b=50, alpha=1.0)

In [10]: color_cls = ColorClass(r=50, g=205, b=50, alpha=1.0)

In [11]: %timeit color_tup.r36.8 ns ± 0.109 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each)

In [12]: %timeit color_cls.r38.4 ns ± 0.112 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each)

In [15]: sys.getsizeof(color_tup)
Out[15]: 72In [16]: sys.getsizeof(color_cls) + sys.getsizeof(vars(color_cls))
Out[16]: 152复制代码

如上,資料類別在中存取欄位的速度稍快一些,但是它們比nametuple佔用更多的記憶體空間。

如何將類型提示新增至namedtuple

資料類別預設使用類型提示。我們也可以將它們放在namedtuples上。透過匯入Namedtuple註解類型並從中繼承,我們可以對Color元組進行註釋。

from typing import NamedTuple
...class Color(NamedTuple):
    """A namedtuple that represents a color."""
    r: float
    g: float
    b: float
    alpha: float复制代码

另一個可能未引起注意的細節是,這種方式也允許我們使用docstring。如果輸入,help(Color)我們將能夠看到它們。

Help on class Color in module __main__:class Color(builtins.tuple)
 |  Color(r: float, g: float, b: float, alpha: Union[float, NoneType])
 |  
 |  A namedtuple that represents a color.
 |  
 |  Method resolution order:
 |      Color
 |      builtins.tuple
 |      builtins.object
 |  
 |  Methods defined here:
 |  
 |  __getnewargs__(self)
 |      Return self as a plain tuple.  Used by copy and pickle.
 |  
 |  __repr__(self)
 |      Return a nicely formatted representation string
 |  
 |  _asdict(self)
 |      Return a new dict which maps field names to their values.复制代码

如何將可選的預設值新增至 namedtuple

在上一節中,我們了解了資料類別可以具有可選值。另外,我提到要模仿上的相同行為,namedtuple需要進行一些技巧修改操作。事實證明,我們可以使用繼承,如下例所示。

from collections import namedtupleclass Color(namedtuple("Color", "r g b alpha")):
    __slots__ = ()    def __new__(cls, r, g, b, alpha=None):
        return super().__new__(cls, r, g, b, alpha)>>> c = Color(r=0, g=0, b=0)>>> c
Color(r=0, g=0, b=0, alpha=None)复制代码

結論

元組是一個非常強大的資料結構。它們使我們的程式碼更清潔,更可靠。儘管與新的資料類別競爭激烈,但他們仍有大量的場景可用。在本教程中,我們學習了使用namedtuples的幾種方法,希望您可以使用它們。

相關免費學習推薦:python影片教學

以上是Python資料結構:一個被低估的Namedtuple(二)的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文轉載於:juejin.im。如有侵權,請聯絡admin@php.cn刪除