概述
一、为什么需要namedtuple或者dataclasses
Python是目前算法从业人员的主流语言,但是许多算法从业人员被没有很好的软件开发基础。这导致算法从业人员的代码通常会滥用字典等数据结构,造成难以阅读和维护的问题。在其他语言中通常会通过类来定义数据结构,这样的好处是:
- 类是对象的抽取,这有助于开发人员对整个代码做high level的设计;
- 定义类的过程通常会添加一定的注释,但是直接使用字典时往往不会特意添加注释;
- 使用类便于复用同一类对象;
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所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复