ホームページ  >  記事  >  バックエンド開発  >  Python データ構造: 過小評価されている名前付きタプル (1)

Python データ構造: 過小評価されている名前付きタプル (1)

coldplay.xixi
coldplay.xixi転載
2020-10-19 17:45:526210ブラウズ

Python チュートリアル 列では、Python データ構造の Namedtuple を紹介します。

Python データ構造: 過小評価されている名前付きタプル (1)

この記事では、Python での namedtuple の主な使用法について説明します。 namedtuple の概念を浅いものから深いものまで紹介していきます。これらを使用する理由と使用方法を学び、結果としてよりクリーンなコードが得られます。このガイドを読んだ後は、このガイドを使いたくなるでしょう。

学習目標

このチュートリアルを終えると、次のことができるようになります。

  • これをいつ使用する理由を理解する
  • 変換通常のタプルと辞書を Namedtuple
  • Namedtuple を辞書または通常のタプルに変換します
  • Namedtuple リストを並べ替えます
  • Namedtuple とデータ クラス (DataClass) の違いを理解する
  • オプションのフィールドを使用して作成するNamedtuple
  • Place NamedtupleJSON へのシリアル化
  • ドキュメント文字列 (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)复制代码

わかりました、大丈夫です。しかし、ここにはいくつかの問題があります。 1 つ目は、戻り値の順序が保証できないことです。つまり、他の開発者が

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}复制代码
わかりました。返される値が 1 つだけであることを期待して、次のように使用できます。

color = convert_string_to_color(desc="blue", alpha=1.0)复制代码
順序を覚える必要はありませんが、少なくとも 2 つの欠点があります。 1 つ目は、追跡する必要があるキーの名前です。

{"r": 0, "g": 0, "b": 0, "alpha": alpha}

{"red": 0, "green" : に変更すると、 0、"blue": 0、"a": alpha}、キー r、g、b が使用されているため、フィールドにアクセスすると KeyError が返されます。 alpha はもう存在しません。 辞書に関する 2 番目の問題は、辞書がハッシュ化できないことです。これは、それらをセットや他の辞書に保存できないことを意味します。特定の画像に含まれる色の数を追跡したいとします。 collections.Counter

を使用してカウントすると、

TypeError: unhashable type: ‘dict’ が返されます。 また、辞書は変更可能であるため、必要なだけ新しいキーを追加できます。信じてください、これらは発見するのが難しい厄介なバグスポットです。

わかりました、いいです。ならどうしよう?代わりに何を使えばいいでしょうか?

名前付きタプル

!はい、それだけです!

関数を変換して 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 の場合と同様に、値を 1 つの変数に代入し、必要に応じて使用できます。順序を覚える必要はありません。さらに、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})复制代码
通常のタプルまたは辞書を名前付きタプルに変換する方法

名前付きタプルが使用される理由を理解したところで、次は通常のタプルと辞書を名前付きタプルに変換する方法を学習します。何らかの理由で、色付きの RGBA 値を含む辞書インスタンスがあるとします。これを

Colornamedtuple

に変換したい場合は、次のように実行できます:

>>> c = {"r": 50, "g": 205, "b": 50, "alpha": alpha}>>> Color(**c)>>> Color(r=50, g=205, b=50, alpha=0)复制代码
** 構造体を使用してパッケージ

を解凍できます。 dict namedtuple です。 dict から nametupe を作成したい場合、どうすればよいですか?

問題ありません。次のようにしてください:

>>> c = {"r": 50, "g": 205, "b": 50, "alpha": alpha}>>> Color = namedtuple("Color", c)>>> Color(**c)
Color(r=50, g=205, b=50, alpha=0)复制代码
dict インスタンスをnamedtuple ファクトリ関数に渡すと、フィールドが作成されます。次に、Color は上記の例のように辞書 c を解凍し、新しいインスタンスを作成します。

如何将 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教程(视频)

以上がPython データ構造: 過小評価されている名前付きタプル (1)の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事はjuejin.imで複製されています。侵害がある場合は、admin@php.cn までご連絡ください。