Die Spalte
Python-Video-Tutorial führt Sie weiterhin zum Verständnis der Namedtuple-Datenstruktur von Python.
Teil 1Python-Datenstruktur: Ein unterschätztes Namedtuple (1)In diesem Artikel wird über einige grundlegende Verwendungsmöglichkeiten von Namedtuple gesprochen.
Vor Python 3.7 konnte ein einfacher Datencontainer mit einer der folgenden Methoden erstellt werden:
attrs
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占用更多的内存空间。
数据类默认使用类型提示。我们也可以将它们放在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
需要进行一些技巧修改操作。事实证明,我们可以使用继承,如下例所示。
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
ul>
__init__
-Methode benötigen, um Eigenschaften während der Klasseninstanziierung festzulegen. Wenn Sie möchten, dass die Klasse hashbar ist, müssen Sie selbst eine __hash__
-Methode implementieren. Um verschiedene Objekte vergleichen zu können, müssen Sie außerdem eine Methode __eq__
implementieren. Um das Debuggen zu vereinfachen, benötigen Sie schließlich eine __repr__
-Methode. Wow! Es ist so einfach, da es keinenLassen Sie uns reguläre Klassen verwenden, um unseren Farbanwendungsfall zu implementieren. rrreeeWie oben müssen Sie viele Methoden implementieren. Sie benötigen lediglich einen Container, der Ihre Daten für Sie speichert, ohne sich um störende Details kümmern zu müssen. Auch hier besteht ein wesentlicher Unterschied, warum Menschen Implementierungsklassen bevorzugen, darin, dass reguläre Klassen veränderbar sind. Tatsächlich bezeichnet der PEP, der die
rrreeeDatenklasse
eingeführt hat, sie als „veränderliches benanntes Tupel mit Standardwert“ (Anmerkung des Übersetzers: Datenklasse eingeführt in Python 3.7, Referenz: docs.python .org/zh- cn/3/lib…Jetzt sehen wir uns an, wie man es mitDatenklassen
macht.
__init__
gibt. Sie definieren das Attribut einfach nach dem Dokumentstring. Zusätzlich zur Veränderlichkeit kann die Klasse auch optionale Felder bereitstellen. Dann ist kein Alphafeld erforderlich Wir können es optional machen 🎜rrreee🎜 Wir können es so instanziieren: 🎜rrreee🎜 Da sie veränderbar sind, können wir alle gewünschten Felder ändern. Transformieren: 🎜rrreee🎜 Im Gegensatz dazu ist dies bei namedtuple
nicht der Fall Um sie hinzuzufügen, benötigen wir einen kleinen Trick und etwas Metaprogrammierung. 🎜🎜Tipp: Um die Methode __hash
hinzuzufügen, müssen Sie sie unveränderlich machen. code> zu True
: 🎜rrreee🎜Ein weiterer Unterschied besteht darin, dass das Entpacken für die Namedtuples-Funktionalität automatisch erfolgt (First-Class-Bürger). Wenn Sie möchten, dass Datenklassen
das gleiche Verhalten haben, Sie müssen es selbst implementieren 🎜rrreeenamedtuple
einige knifflige Änderungen erforderlich sind. Es stellt sich heraus, dass wir die Vererbung wie im folgenden Beispiel verwenden können. 🎜rrreeeDatenklassen
steht ihnen immer noch eine große Anzahl von Szenarien zur Verfügung. In diesem Tutorial haben wir verschiedene Möglichkeiten zur Verwendung von namedtuples
kennengelernt und hoffen, dass Sie diese verwenden können. 🎜🎜🎜🎜Verwandte kostenlose Lernempfehlungen: 🎜🎜🎜Python-Video-Tutorial🎜🎜🎜🎜Das obige ist der detaillierte Inhalt vonPython-Datenstruktur: ein unterschätztes Namedtuple (2). Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!