Pythonビデオチュートリアルの列には、Pythonデータ構造のnamedtupleが引き続き表示されます。
Pythonデータ構造の最後の部分:過小評価されているNamedtuple(1)は、namedtupleの基本的な使用法について説明しましたが、この記事は続きます。
名前付きタプルとデータクラスの違いは何ですか?
関数Python3.7
より前では、次のいずれかの方法を使用して、単純なデータコンテナを作成できます。
namedtuple
レギュラークラス
サードパーティライブラリ、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
)复制代码
上記のように、多くのメソッドを実装する必要があります。詳細を気にすることなく、データを保持するためのコンテナのみが必要です。同様に、実装クラスに対する人々の好みの主な違いは、通常のクラスは変更可能であるということです。
実際、データクラスを導入したPEPは、それらを「デフォルト値を持つ変数namedtuples」と呼んでいました(翻訳者注:データクラス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クラスにアルファフィールドが必要ないとします。次に、それをオプションとして設定できます。
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:
...复制代码
もう1つの違いは、開梱は名前付きタプルの第一級市民であるということです。データクラスに同じ動作を持たせたい場合は、自分で実装する必要があります。
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)复制代码
パフォーマンスの比較
関数だけを比較するだけでは不十分であり、名前付きタプルとデータクラスもパフォーマンスが異なります。データクラスは、純粋なPythonに基づいてdictを実装します。これにより、フィールドにアクセスする際の速度が向上します。一方、namedtupleは、通常の拡張タプルです。これは、それらの実装がより高速なCコードに基づいており、メモリフットプリントが小さいことを意味します。
この点を証明するために、Python3.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よりも多くのメモリスペースを消費します。
名前付きtuple
データクラスに型ヒントを追加する方法は、デフォルトで型ヒントを使用します。名前付きのタプルに配置することもできます。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.复制代码
指定されたtupleにオプションのデフォルト値を追加する方法
前のセクションでは、データクラスがオプションの値を持つことができることを学びました。さらに、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を使用するいくつかの方法を学び、それらを使用できることを願っています。
この記事は、php中国語のWebサイトにあるPythonビデオチュートリアルからのものです:https://www.php.cn/course/list/30.html