Die Spalte „Python-Tutorial“ führt Sie in das Namedtuple in der Python-Datenstruktur ein.
In diesem Artikel wird die Hauptverwendung vonnamedtuple
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.
Namedtuple
Namedtuple
in Wörterbücher oder reguläre Tupel Sortieren Sie die Namedtuple
-ListeNamedtuple
und der Datenklasse (DataClass) mit optionalen Feldern Namedtuple code>
Namedtuple
in JSON serialisierennamedtuple
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
序列化为JSONnamedtuple
?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,b
和alpha
不再存在。
字典的第二个问题是它们不可散列。这意味着我们无法将它们存储在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了。假设由于某种原因,你有包含彩色RGBA值的字典实例。如果要将其转换为Color namedtuple
,则可以按以下步骤进行:
>>> c = {"r": 50, "g": 205, "b": 50, "alpha": alpha}>>> Color(**c)>>> Color(r=50, g=205, b=50, alpha=0)复制代码
我们可以利用该**
结构将包解压缩dict
为namedtuple
>>> c = {"r": 50, "g": 205, "b": 50, "alpha": alpha}>>> Color = namedtuple("Color", c)>>> Color(**c) Color(r=50, g=205, b=50, alpha=0)复制代码
so aufzurufen. Außerdem wissen wir möglicherweise nicht, dass die Funktion 4 Werte zurückgibt, und rufen die Funktion möglicherweise so auf:>>> blue = Color(r=0, g=0, b=255, alpha=1.0)>>> blue._asdict() {'r': 0, 'g': 0, 'b': 255, 'alpha': 1.0}复制代码Nach dem Login kopierenNach dem Login kopierenOkay, 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)复制代码Nach dem Login kopierenNach dem Login kopieren
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)]复制代码
ValueError
Fehler 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}'复制代码
_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)复制代码
{"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 """复制代码
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. 🎜rrreeeColor 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
为dict
。反过来呢?我们又如何将其转换为字典实例?
实验证明,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)复制代码
另一个常见的用例是将多个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强度升序排列!
有时你可能需要将储存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}'复制代码
在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!