ホームページ >バックエンド開発 >Python チュートリアル >Python データ構造: 過小評価されている名前付きタプル (1)
Python チュートリアル 列では、Python データ構造の Namedtuple を紹介します。
この記事では、Python での namedtuple
の主な使用法について説明します。 namedtuple
の概念を浅いものから深いものまで紹介していきます。これらを使用する理由と使用方法を学び、結果としてよりクリーンなコードが得られます。このガイドを読んだ後は、このガイドを使いたくなるでしょう。
このチュートリアルを終えると、次のことができるようになります。
Namedtuple
Namedtuple
を辞書または通常のタプルに変換しますNamedtuple
リストを並べ替えますNamedtuple
とデータ クラス (DataClass) の違いを理解するNamedtuple
Namedtuple
JSON へのシリアル化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
エラーがスローされ、呼び出しは失敗します。 #########確かに。しかし、なぜ辞書を使わないのかと疑問に思うかもしれません。
わかりました。返される値が 1 つだけであることを期待して、次のように使用できます。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)复制代码順序を覚える必要はありませんが、少なくとも 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 値を含む辞書インスタンスがあるとします。これを
>>> c = {"r": 50, "g": 205, "b": 50, "alpha": alpha}>>> Color(**c)>>> Color(r=50, g=205, b=50, alpha=0)复制代码
** 構造体を使用してパッケージ を解凍できます。 dict は
namedtuple です。
dict から nametupe を作成したい場合、どうすればよいですか?
dict インスタンスをnamedtuple ファクトリ関数に渡すと、フィールドが作成されます。次に、Color は上記の例のように辞書 c を解凍し、新しいインスタンスを作成します。問題ありません。次のようにしてください:
>>> c = {"r": 50, "g": 205, "b": 50, "alpha": alpha}>>> Color = namedtuple("Color", c)>>> Color(**c) Color(r=50, g=205, b=50, alpha=0)复制代码
我们刚刚学习了如何将转换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教程(视频)
以上がPython データ構造: 過小評価されている名前付きタプル (1)の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。