>백엔드 개발 >파이썬 튜토리얼 >Python 데이터 구조: 과소평가된 명명된 튜플(1)

Python 데이터 구조: 과소평가된 명명된 튜플(1)

coldplay.xixi
coldplay.xixi앞으로
2020-10-19 17:45:526359검색

Python 튜토리얼 열에서는 Python 데이터 구조의 Namedtuple을 소개합니다.

Python 데이터 구조: 과소평가된 명명된 튜플(1)

이 기사에서는 Python에서 namedtuple의 주요 사용법에 대해 설명합니다. namedtuple의 개념을 더 얕은 것부터 더 깊은 것까지 소개하겠습니다. 이를 사용하는 이유와 사용 방법을 배우면 더 깔끔한 코드가 생성됩니다. 이 가이드를 공부한 후에는 즐겨 사용하게 될 것입니다. 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

학습 목표

이 튜토리얼이 끝나면 다음을 수행할 수 있어야 합니다.
  • 이 튜토리얼을 사용하는 이유와 시기 이해
  • 일반 튜플과 사전을 Namedtuple로 변환
  • Namedtuple을 사전이나 일반 튜플로 변환
  • Namedtuple 목록 정렬
  • Namedtuple과 데이터 클래스(DataClass)의 차이점 이해
  • 선택 필드 Namedtuple을 사용하여 만들기
  • code>
  • Namedtuple을 JSON으로 직렬화
  • 문서 문자열(docstring) 추가

namedtuple을 사용하는 이유는 무엇입니까?

namedtuple은 매우 흥미롭고 과소평가된 데이터 구조입니다. 데이터를 저장하기 위해 일반 튜플과 사전에 크게 의존하는 Python 코드를 쉽게 찾을 수 있습니다. 그게 나쁘다고 말하는 게 아니라, 가끔 학대를 당하는 경우가 많다는 점을 말씀드리겠습니다.

문자열을 색상으로 변환하는 함수가 있다고 가정해보세요. 색상은 4차원 공간 RGBA로 표현되어야 합니다.

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)复制代码
알겠습니다. 하지만 여기에는 몇 가지 문제가 있습니다. 첫 번째는 반환되는 값의 순서를 보장할 수 없다는 점이다. 즉, 다른 개발자가 이렇게

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)复制代码
{"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

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复制代码

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

>>> 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'复制代码

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

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

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

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

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

现在我们了解了为什么使用namedtuple,现在该学习如何将常规元组和字典转换为namedtuple了。假设由于某种原因,你有包含彩色RGBA值的字典实例。如果要将其转换为Color 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)复制代码

我们可以利用该**结构将包解压缩dictnamedtuple를 호출하는 것을 막을 방법이 없습니다. 게다가 우리는 함수가 4개의 값을 반환한다는 것을 모르고 다음과 같이 함수를 호출할 수도 있습니다. 값이 충분하지 않아 ValueError 오류가 발생하고 호출이 실패했습니다.

맞습니다. 하지만 사전을 사용하면 어떨까?

Python의 사전은 매우 다양한 데이터 구조입니다. 여러 값을 저장하는 편리한 방법입니다. 그러나 사전에도 단점이 없는 것은 아닙니다. 유연성 때문에 사전은 쉽게 남용됩니다. 허락하다 사전을 사용하여 예를 살펴보겠습니다.

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

좋아, 이제 다음과 같이 하나의 값만 반환될 것으로 예상하여 다음과 같이 사용할 수 있습니다.

>>> tuple(Color(r=50, g=205, b=50, alpha=0.1))
(50, 205, 50, 0.1)复制代码
🎜순서를 기억할 필요는 없지만 적어도 두 가지 단점이 있습니다. 첫 번째는 우리가 추적해야 하는 키의 이름입니다. {"r": 0, "g": 0, "b": 0, "alpha": alpha}에서 {"red": 0, "green으로 변경하면 ”: 0, “blue”: 0, “a”: alpha}, 키가 r, g, bKeyError가 발생합니다. /code> code> 및 alpha는 더 이상 존재하지 않습니다. 🎜🎜사전의 두 번째 문제점은 해시 가능하지 않다는 것입니다. 즉, 세트나 다른 사전에 저장할 수 없습니다. 특정 이미지에 얼마나 많은 색상이 있는지 추적하고 싶다고 가정해 보겠습니다. collections.Counter를 사용하여 계산하면 TypeError: unhashable type: 'dict'가 발생합니다. 🎜🎜또한 사전은 변경 가능하므로 필요한 만큼 새 키를 추가할 수 있습니다. 저를 믿으십시오. 이것은 발견하기 어려운 불쾌한 버그 지점입니다. 🎜🎜알겠습니다. 그럼 이제 어떡하지? 대신 무엇을 사용할 수 있나요? 🎜🎜네임튜플! 예, 바로 그거예요! 🎜🎜 namedtuple을 사용하도록 함수를 변환합니다. 🎜
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)]复制代码
🎜 dict의 경우와 마찬가지로 값을 단일 변수에 할당하고 필요에 따라 사용할 수 있습니다. 순서를 기억할 필요가 없습니다. 또한 PyCharm 및 VSCode와 같은 IDE를 사용하는 경우 자동으로 완료 메시지를 표시할 수도 있습니다. 🎜
>>> 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이 변경 불가능하다는 것입니다. 팀의 다른 개발자가 런타임에 새 필드를 추가하는 것이 좋다고 생각하면 프로그램에서 오류를 보고합니다. 🎜
_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)复制代码
🎜 그뿐만 아니라 이제 Counter를 사용하여 컬렉션에 포함된 색상 수를 추적할 수 있습니다. 🎜
>>> Color.__doc__ = """A namedtuple that represents a color.
    It has 4 fields:
    r - red
    g - green
    b - blue
    alpha - the alpha channel
    """复制代码

일반 튜플이나 사전을 네임드튜플로 변환하는 방법

🎜이제 네임드튜플이 사용되는 이유를 이해했으므로 일반 튜플과 사전을 네임드튜플로 변환하는 방법을 알아볼 차례입니다. . 어떤 이유로 색상이 지정된 RGBA 값을 포함하는 사전 인스턴스가 있다고 가정해 보겠습니다. Color namestuple로 변환하려면 아래 단계를 따르세요. 🎜rrreee🎜 ** 구조를 사용하여 dict는 <code>namedtuple입니다. 🎜🎜🎜dict에서 네임드튜페를 만들고 싶다면 어떻게 해야 하나요? 🎜🎜🎜문제 없습니다. 다음과 같이 하세요: 🎜rrreee🎜 dict 인스턴스를 명명된 튜플 팩토리 함수에 전달하면 필드가 생성됩니다. 그런 다음 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 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
이 기사는 juejin.im에서 복제됩니다. 침해가 있는 경우 admin@php.cn으로 문의하시기 바랍니다. 삭제