Heim  >  Artikel  >  Backend-Entwicklung  >  Python-Datenstrukturen: Ein unterschätztes benanntes Tupel (1)

Python-Datenstrukturen: Ein unterschätztes benanntes Tupel (1)

coldplay.xixi
coldplay.xixinach vorne
2020-10-19 17:45:526210Durchsuche

Die Spalte „Python-Tutorial“ führt Sie in das Namedtuple in der Python-Datenstruktur ein.

In diesem Artikel wird die Hauptverwendung von namedtuple in Python erläutert. Wir werden die Konzepte von namedtuple von der Tiefe zur Tiefe einführen. Sie erfahren, warum Sie sie verwenden und wie Sie sie verwenden, was zu saubererem Code führt. Nachdem Sie diesen Leitfaden studiert haben, werden Sie ihn gerne verwenden.

Lernziele

Am Ende dieses Tutorials sollten Sie in der Lage sein: Python-Datenstrukturen: Ein unterschätztes benanntes Tupel (1)
  • Verstehen, warum und wann Sie es verwenden sollten
  • Konvertieren Sie reguläre Tupel und Wörterbücher in Namedtuple
  • Konvertieren Sie Namedtuple in Wörterbücher oder reguläre Tupel
  • in Sortieren Sie die Namedtuple-Liste
  • Verstehen Sie den Unterschied zwischen Namedtuple und der Datenklasse (DataClass)
  • Erstellen Sie mit optionalen Feldern Namedtuple code>
  • Namedtuple in JSON serialisieren
  • Dokumentationszeichenfolge (docstring) hinzufügen

Warum namedtuple verwenden?

namedtuple ist eine sehr interessante (und unterschätzte) Datenstruktur. Wir können leicht Python-Code finden, der zum Speichern von Daten stark auf regulären Tupeln und Wörterbüchern basiert. Ich sage nicht, dass das schlecht ist, es ist nur so, dass sie manchmal oft missbraucht werden, das kann ich Ihnen sagen.

Angenommen, Sie haben eine Funktion, die eine Zeichenfolge in eine Farbe umwandelt. Farbe muss im 4-dimensionalen RGBA-Raum dargestellt werden. namedtuple的重点用法。我们将由浅入深的介绍namedtuple的各概念。您将了解为什么要使用它们,以及如何使用它们,从而是代码更简洁。在学习本指南之后,你一定会喜欢上使用它。

学习目标

在本教程结束时,您应该能够:

  • 了解为什么以及何时使用它
  • 将常规元组和字典转换为Namedtuple
  • Namedtuple转化为字典或常规元组
  • Namedtuple列表进行排序
  • 了解Namedtuple和数据类(DataClass)之间的区别
  • 使用可选字段创建Namedtuple
  • Namedtuple序列化为JSON
  • 添加文档字符串(docstring)

为什么要使用namedtuple

namedtuple是一个非常有趣(也被低估了)的数据结构。我们可以轻松找到严重依赖常规元组和字典来存储数据的Python代码。我并不是说,这样不好,只是有时候他们常常被滥用,且听我慢慢道来。

假设你有一个将字符串转换为颜色的函数。颜色必须在4维空间RGBA中表示。

def convert_string_to_color(desc: str, alpha: float = 0.0):
    if desc == "green":        return 50, 205, 50, alpha    elif desc == "blue":        return 0, 0, 255, alpha    else:        return 0, 0, 0, alpha复制代码

然后,我们可以像这样使用它:

r, g, b, a = convert_string_to_color(desc="blue", alpha=1.0)复制代码

好的,可以。但是我们这里有几个问题。第一个是,无法确保返回值的顺序。也就是说,没有什么可以阻止其他开发者这样调用

convert_string_to_color:
g, b, r, a = convert_string_to_color(desc="blue", alpha=1.0)复制代码

另外,我们可能不知道该函数返回4个值,可能会这样调用该函数:

r, g, b = convert_string_to_color(desc="blue", alpha=1.0)复制代码

于是,因为返回值不够,抛出ValueError错误,调用失败。

确实如此。但是,你可能会问,为什么不使用字典呢?

Python的字典是一种非常通用的数据结构。它们是一种存储多个值的简便方法。但是,字典并非没有缺点。由于其灵活性,字典很容易被滥用。让 我们看看使用字典之后的例子。

def convert_string_to_color(desc: str, alpha: float = 0.0):
    if desc == "green":        return {"r": 50, "g": 205, "b": 50, "alpha": alpha}    elif desc == "blue":        return {"r": 0, "g": 0, "b": 255, "alpha": alpha}    else:        return {"r": 0, "g": 0, "b": 0, "alpha": alpha}复制代码

好的,我们现在可以像这样使用它,期望只返回一个值:

color = convert_string_to_color(desc="blue", alpha=1.0)复制代码

无需记住顺序,但它至少有两个缺点。第一个是我们必须跟踪密钥的名称。如果我们将其更改{"r": 0, “g”: 0, “b”: 0, “alpha”: alpha}{”red": 0, “green”: 0, “blue”: 0, “a”: alpha},则在访问字段时会得到KeyError返回,因为键r,g,balpha不再存在。

字典的第二个问题是它们不可散列。这意味着我们无法将它们存储在set或其他字典中。假设我们要跟踪特定图像有多少种颜色。如果我们使用collections.Counter计数,我们将得到TypeError: unhashable type: ‘dict’

而且,字典是可变的,因此我们可以根据需要添加任意数量的新键。相信我,这是一些很难发现的令人讨厌的错误点。

好的,很好。那么现在怎么办?我可以用什么代替呢?

namedtuple!对,就是它!

将我们的函数转换为使用namedtuple

from collections import namedtuple
...
Color = namedtuple("Color", "r g b alpha")
...def convert_string_to_color(desc: str, alpha: float = 0.0):
    if desc == "green":        return Color(r=50, g=205, b=50, alpha=alpha)    elif desc == "blue":        return Color(r=50, g=0, b=255, alpha=alpha)    else:        return Color(r=50, g=0, b=0, alpha=alpha)复制代码

与dict的情况一样,我们可以将值分配给单个变量并根据需要使用。无需记住顺序。而且,如果你使用的是诸如PyCharm和VSCode之类的IDE ,还可以自动提示补全。

color = convert_string_to_color(desc="blue", alpha=1.0)
...
has_alpha = color.alpha > 0.0...
is_black = color.r == 0 and color.g == 0 and color.b == 0复制代码

最重要的是namedtuple是不可变的。如果团队中的另一位开发人员认为在运行时添加新字段是个好主意,则该程序将报错。

>>> blue = Color(r=0, g=0, b=255, alpha=1.0)>>> blue.e = 0---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
<ipython-input-13-8c7f9b29c633> in <module>
----> 1 blue.e = 0AttributeError: 'Color' object has no attribute 'e'复制代码

不仅如此,现在我们可以使用它Counter来跟踪一个集合有多少种颜色。

>>> Counter([blue, blue])>>> Counter({Color(r=0, g=0, b=255, alpha=1.0): 2})复制代码

如何将常规元组或字典转换为 namedtuple

现在我们了解了为什么使用namedtuple,现在该学习如何将常规元组和字典转换为namedtuple了。假设由于某种原因,你有包含彩色RGBA值的字典实例。如果要将其转换为Color namedtuple,则可以按以下步骤进行:

>>> c = {"r": 50, "g": 205, "b": 50, "alpha": alpha}>>> Color(**c)>>> Color(r=50, g=205, b=50, alpha=0)复制代码

我们可以利用该**结构将包解压缩dictnamedtuple

>>> c = {"r": 50, "g": 205, "b": 50, "alpha": alpha}>>> Color = namedtuple("Color", c)>>> Color(**c)
Color(r=50, g=205, b=50, alpha=0)复制代码
Dann können wir es so verwenden:
>>> blue = Color(r=0, g=0, b=255, alpha=1.0)>>> blue._asdict()
{'r': 0, 'g': 0, 'b': 255, 'alpha': 1.0}复制代码

Okay, klar. Aber wir haben hier mehrere Probleme. Der erste besteht darin, dass die Reihenfolge der zurückgegebenen Werte nicht garantiert werden kann. Das heißt, nichts hindert andere Entwickler daran,

>>> tuple(Color(r=50, g=205, b=50, alpha=0.1))
(50, 205, 50, 0.1)复制代码
so aufzurufen. Außerdem wissen wir möglicherweise nicht, dass die Funktion 4 Werte zurückgibt, und rufen die Funktion möglicherweise so auf:

from operator import attrgetter
...
colors = [
    Color(r=50, g=205, b=50, alpha=0.1),
    Color(r=50, g=205, b=50, alpha=0.5),
    Color(r=50, g=0, b=0, alpha=0.3)
]
...>>> sorted(colors, key=attrgetter("alpha"))
[Color(r=50, g=205, b=50, alpha=0.1),
 Color(r=50, g=0, b=0, alpha=0.3),
 Color(r=50, g=205, b=50, alpha=0.5)]复制代码
Also, weil die Rückgabe Der Wert reicht nicht aus, es wird ein ValueErrorFehler ausgegeben, der Aufruf ist fehlgeschlagen.

🎜Das stimmt. Aber Sie fragen sich vielleicht, warum nicht ein Wörterbuch verwenden? 🎜🎜🎜Pythons Wörterbuch ist eine sehr vielseitige Datenstruktur. Sie sind eine praktische Möglichkeit, mehrere Werte zu speichern. Allerdings sind Wörterbücher nicht ohne Nachteile. Aufgrund ihrer Flexibilität können Wörterbücher leicht missbraucht werden. lassen Schauen wir uns ein Beispiel mit einem Wörterbuch an. 🎜
>>> blue = Color(r=0, g=0, b=255, alpha=1.0)>>> import json>>> json.dumps(blue._asdict())'{"r": 0, "g": 0, "b": 255, "alpha": 1.0}'复制代码
🎜Okay, wir können es jetzt so verwenden und erwarten, dass nur ein Wert zurückgegeben wird: 🎜
_Color = namedtuple("Color", "r g b alpha")

class Color(_Color):
    """A namedtuple that represents a color.
    It has 4 fields:
    r - red
    g - green
    b - blue
    alpha - the alpha channel
    """

>>> print(Color.__doc__)
A namedtuple that represents a color.
    It has 4 fields:
    r - red
    g - green
    b - blue
    alpha - the alpha channel
>>> help(Color)
Help on class Color in module __main__:

class Color(Color)
 |  Color(r, g, b, alpha)
 |  
 |  A namedtuple that represents a color.
 |  It has 4 fields:
 |  r - red
 |  g - green
 |  b - blue
 |  alpha - the alpha channel
 |  
 |  Method resolution order:
 |      Color
 |      Color
 |      builtins.tuple
 |      builtins.object
 |  
 |  Data descriptors defined here:
 |  
 |  __dict__
 |      dictionary for instance variables (if defined)复制代码
🎜Sie müssen sich die Reihenfolge nicht merken, aber sie hat mindestens zwei Nachteile. Der erste ist der Name des Schlüssels, den wir im Auge behalten müssen. Wenn wir es von {"r": 0, "g": 0, "b": 0, "alpha": alpha} in {"red": 0, "green" ändern ”: 0, „blue“: 0, „a“: alpha, Sie erhalten KeyError, wenn Sie auf das Feld zugreifen, da die Schlüssel r, g, b code> und <code>alpha existieren nicht mehr. 🎜🎜Das zweite Problem bei Wörterbüchern besteht darin, dass sie nicht hashbar sind. Das bedeutet, dass wir sie nicht in einem Set oder einem anderen Wörterbuch speichern können. Nehmen wir an, wir möchten verfolgen, wie viele Farben ein bestimmtes Bild hat. Wenn wir zum Zählen collections.Counter verwenden, erhalten wir TypeError: unhashable type: ‘dict’. 🎜🎜Außerdem sind Wörterbücher veränderbar, sodass wir so viele neue Schlüssel hinzufügen können, wie wir benötigen. Vertrauen Sie mir, das sind einige böse Fehlerstellen, die schwer zu erkennen sind. 🎜🎜Okay, gut. Was nun? Was kann ich stattdessen verwenden? 🎜🎜namedtuple! Ja, das ist es! 🎜🎜 Wandeln Sie unsere Funktion um, um namedtuple zu verwenden: 🎜
>>> Color.__doc__ = """A namedtuple that represents a color.
    It has 4 fields:
    r - red
    g - green
    b - blue
    alpha - the alpha channel
    """复制代码
🎜 Wie bei dict können wir den Wert einer einzelnen Variablen zuweisen und ihn nach Bedarf verwenden. Sie müssen sich die Bestellung nicht merken. Wenn Sie IDEs wie PyCharm und VSCode verwenden, können Sie außerdem automatisch zum Abschluss auffordern. 🎜rrreee🎜Das Wichtigste ist, dass namedtuple unveränderlich ist. Wenn ein anderer Entwickler im Team es für eine gute Idee hält, zur Laufzeit ein neues Feld hinzuzufügen, meldet das Programm einen Fehler. 🎜rrreee🎜 Nicht nur das, jetzt können wir Counter verwenden, um zu verfolgen, wie viele Farben eine Kollektion hat. 🎜rrreee

So konvertieren Sie reguläre Tupel oder Wörterbücher in „namedtuple“

🎜Da wir nun verstehen, warum „namedtuple“ verwendet wird, ist es an der Zeit zu lernen, wie Sie reguläre Tupel und Wörterbücher in „namedtuple“ konvertieren . Nehmen wir an, Sie haben aus irgendeinem Grund eine Wörterbuchinstanz, die farbige RGBA-Werte enthält. Wenn Sie es in Color benannttuple konvertieren möchten, können Sie die folgenden Schritte ausführen: 🎜rrreee🎜Wir können die **-Struktur verwenden, um das Paket dict ist <code>namedtuple. 🎜🎜🎜Wenn ich aus dict ein NamedTupe erstellen möchte, wie mache ich das? 🎜🎜🎜Kein Problem, machen Sie einfach Folgendes: 🎜rrreee🎜Indem Sie die dict-Instanz an die Namedtuple-Factory-Funktion übergeben, werden die Felder für Sie erstellt. Anschließend entpackt Color das Wörterbuch c wie im obigen Beispiel und erstellt eine neue Instanz. 🎜

如何将 namedtuple 转换为字典或常规元组

我们刚刚学习了如何将转换namedtupledict。反过来呢?我们又如何将其转换为字典实例?

实验证明,namedtuple它带有一种称为的方法._asdict()。因此,转换它就像调用方法一样简单。

>>> blue = Color(r=0, g=0, b=255, alpha=1.0)>>> blue._asdict()
{'r': 0, 'g': 0, 'b': 255, 'alpha': 1.0}复制代码

您可能想知道为什么该方法以_开头。这是与Python的常规规范不一致的一个地方。通常,_代表私有方法或属性。但是,namedtuple为了避免命名冲突将它们添加到了公共方法中。除了_asdict,还有_replace_fields_field_defaults。您可以在这里找到所有这些。

要将namedtupe转换为常规元组,只需将其传递给tuple构造函数即可。

>>> tuple(Color(r=50, g=205, b=50, alpha=0.1))
(50, 205, 50, 0.1)复制代码

如何对namedtuples列表进行排序

另一个常见的用例是将多个namedtuple实例存储在列表中,并根据某些条件对它们进行排序。例如,假设我们有一个颜色列表,我们需要按alpha强度对其进行排序。

幸运的是,Python允许使用非常Python化的方式来执行此操作。我们可以使用operator.attrgetter运算符。根据文档,attrgetter“返回从其操作数获取attr的可调用对象”。简单来说就是,我们可以通过该运算符,来获取传递给sorted函数排序的字段。例:

from operator import attrgetter
...
colors = [
    Color(r=50, g=205, b=50, alpha=0.1),
    Color(r=50, g=205, b=50, alpha=0.5),
    Color(r=50, g=0, b=0, alpha=0.3)
]
...>>> sorted(colors, key=attrgetter("alpha"))
[Color(r=50, g=205, b=50, alpha=0.1),
 Color(r=50, g=0, b=0, alpha=0.3),
 Color(r=50, g=205, b=50, alpha=0.5)]复制代码

现在,颜色列表按alpha强度升序排列!

如何将namedtuples序列化为JSON

有时你可能需要将储存namedtuple转为JSON。Python的字典可以通过json模块转换为JSON。那么我们可以使用_asdict方法将元组转换为字典,然后接下来就和字典一样了。例如:

>>> blue = Color(r=0, g=0, b=255, alpha=1.0)>>> import json>>> json.dumps(blue._asdict())'{"r": 0, "g": 0, "b": 255, "alpha": 1.0}'复制代码

如何给namedtuple添加docstring

在Python中,我们可以使用纯字符串来记录方法,类和模块。然后,此字符串可作为名为的特殊属性使用__doc__。话虽这么说,我们如何向我们的Color namedtuple添加docstring的?

我们可以通过两种方式做到这一点。第一个(比较麻烦)是使用包装器扩展元组。这样,我们便可以docstring在此包装器中定义。例如,请考虑以下代码片段:

_Color = namedtuple("Color", "r g b alpha")

class Color(_Color):
    """A namedtuple that represents a color.
    It has 4 fields:
    r - red
    g - green
    b - blue
    alpha - the alpha channel
    """

>>> print(Color.__doc__)
A namedtuple that represents a color.
    It has 4 fields:
    r - red
    g - green
    b - blue
    alpha - the alpha channel
>>> help(Color)
Help on class Color in module __main__:

class Color(Color)
 |  Color(r, g, b, alpha)
 |  
 |  A namedtuple that represents a color.
 |  It has 4 fields:
 |  r - red
 |  g - green
 |  b - blue
 |  alpha - the alpha channel
 |  
 |  Method resolution order:
 |      Color
 |      Color
 |      builtins.tuple
 |      builtins.object
 |  
 |  Data descriptors defined here:
 |  
 |  __dict__
 |      dictionary for instance variables (if defined)复制代码

如上,通过继承_Color元组,我们为namedtupe添加了一个__doc__属性。

添加的第二种方法,直接设置__doc__属性。这种方法不需要扩展元组。

>>> Color.__doc__ = """A namedtuple that represents a color.
    It has 4 fields:
    r - red
    g - green
    b - blue
    alpha - the alpha channel
    """复制代码

注意,这些方法仅适用于Python 3+

限于篇幅,先到这下篇继续。

相关免费学习推荐:python教程(视频)

Das obige ist der detaillierte Inhalt vonPython-Datenstrukturen: Ein unterschätztes benanntes Tupel (1). Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Dieser Artikel ist reproduziert unter:juejin.im. Bei Verstößen wenden Sie sich bitte an admin@php.cn löschen