我是靠谱客的博主 标致小笼包,最近开发中收集的这篇文章主要介绍【Python】namedtuple和dataclasses,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

一、为什么需要namedtuple或者dataclasses

Python是目前算法从业人员的主流语言,但是许多算法从业人员被没有很好的软件开发基础。这导致算法从业人员的代码通常会滥用字典等数据结构,造成难以阅读和维护的问题。在其他语言中通常会通过类来定义数据结构,这样的好处是:

  1. 类是对象的抽取,这有助于开发人员对整个代码做high level的设计;
  2. 定义类的过程通常会添加一定的注释,但是直接使用字典时往往不会特意添加注释;
  3. 使用类便于复用同一类对象;

namedtuple和dataclasses其实就是python提供的一种方便的数据类定义方式,在项目复杂度较高的情况下请多使用这两种数据结构。

二、namedtuple

1. 定义namedtuple

from collections import namedtuple

# 定义一个名为Point的namedtuple,其包含属性x和y(类似于定义了一个名为Point的类)
Point = namedtuple("Point", ("x", "y"))
# 实例化namedtuple(基于类Point创建对象)
p1 = Point(x=1,y=2)
print(p1)
print(p1.x)
print(p1.y)
Point(x=1, y=2)
1
2

2. namedtuple不鼓励修改属性值

# 直接修改会抛出异常
p1.x = 0
---------------------------------------------------------------------------

AttributeError                            Traceback (most recent call last)

<ipython-input-2-0a2640ccc19a> in <module>
      1 # 直接修改会抛出异常
----> 2 p1.x = 0


AttributeError: can't set attribute
# 需要使用_replace方法进行修改
# _replace方法会返回一个新对象,而不是修改原有对象
p1 = p1._replace(x=0)
print(p1)
Point(x=0, y=2)

3. 为namedtuple设置默认值

# python3.7之前
Point = namedtuple("Point",("x", "y"))
Point.__new__.__defaults__ = (0, 0)
p1 = Point()
print(p1)
# python3.7之后
Point = namedtuple("Point", ("x", "y"), defaults=(1,1))
p1 = Point()
print(p1)
Point(x=0, y=0)
Point(x=1, y=1)

4. namedtuple与字典的相互转换

# namedtuple转字典
p1_dict = p1._asdict()
print(p1_dict)
# 字典转namedtuple
p2 = Point(**p1_dict)
print(p2)
{'x': 1, 'y': 1}
Point(x=1, y=1)

三、dataclasses

namedtuple本质上是一个数据容器,但是从功能上看其并不完整。因此,在Python3.7之前只能通过自定义类的方式实现自定义数据容器。但是,这通常需要用户自己实现__init____hash____eq____repr__等方法。在Python3.7提供了dataclasses,其可以看做是带有默认值的可变namedtuple。其主要特点有:

  • 通常不包含私有属性(数据容器通常不需要私有属性)
  • 拥有默认的、固定格式的__repr__方法;
  • 由于默认的__eq____hash__方法;

1. 使用dataclasses

from dataclasses import dataclass

@dataclass
class Point:
    "A Point"
    x: float = -1
    y: float = -1
        
p1 = Point(x=0, y=0)
print(p1)
print(p1.x)
print(p1.y)
p1.x = 1 # 可以修改
print(p1)
p2 = Point(1,0)
print(p1==p2)
Point(x=0, y=0)
0
0
Point(x=1, y=0)
True

2. __post_init__

dataclass提供了__post_init__方法,该方法会在初始化方法__init__调用后自动调用。其可以用于初始化那些需要前置条件的变量。

@dataclass
class Point:
    "A Point"
    x: float = 1
    y: float = 1
    len_: float = None
        
    def __post_init__(self):
        self.len_ = (self.x**2 + self.y**2)**0.5
        
p = Point()
print(p)
Point(x=1, y=1, len_=1.4142135623730951)

3. Field

from dataclasses import field
from uuid import UUID, uuid4


@dataclass
class Point:
    x: float = 1
    y: float = 1
    # default_factory接收一个无参函数
    # 作用是:若初始化时未指定该变量的值,则使用default_factory函数的返回值来初始化
    # compare=False,在比较两个点时不比较该变量值
    id_: UUID = field(default_factory=uuid4, compare=False)

p1 = Point()
p2 = Point()
print(p1)
print(p2)
print(p1==p2)
Point(x=1, y=1, id_=UUID('fe0cd212-adff-44e1-b81d-968e08745a4f'))
Point(x=1, y=1, id_=UUID('ee8edb7b-f190-4715-8d4a-231b5b705092'))
True

最后

以上就是标致小笼包为你收集整理的【Python】namedtuple和dataclasses的全部内容,希望文章能够帮你解决【Python】namedtuple和dataclasses所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(44)

评论列表共有 0 条评论

立即
投稿
返回
顶部