我的编程空间,编程开发者的网络收藏夹
学习永远不晚

Python3.7 dataclass使

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

Python3.7 dataclass使

本文将带你走进python3.7的新特性dataclass,通过本文你将学会dataclass的使用并避免踏入某些陷阱。

  • dataclass简介
  • dataclass的使用
    • 定义一个dataclass
    • 深入dataclass装饰器
    • 数据类的基石——dataclasses.field
    • 一些常用函数
    • dataclass继承
  • 总结

dataclass简介

dataclass的定义位于PEP-557,根据定义一个dataclass是指“一个带有默认值的可变的namedtuple”,广义的定义就是有一个类,它的属性均可公开访问,可以带有默认值并能被修改,而且类中含有与这些属性相关的类方法,那么这个类就可以称为dataclass,再通俗点讲,dataclass就是一个含有数据及操作数据方法的容器。

乍一看可能会觉得这个概念不就是普通的class么,然而还是有几处不同:

  1. 相比普通class,dataclass通常不包含私有属性,数据可以直接访问
  2. dataclass的repr方法通常有固定格式,会打印出类型名以及属性名和它的值
  3. dataclass拥有__eq____hash__魔法方法
  4. dataclass有着模式单一固定的构造方式,或是需要重载运算符,而普通class通常无需这些工作

基于上述原因,通常自己实现一个dataclass是繁琐而无聊的,而dataclass单一固定的行为正适合程序为我们自动生成,于是dataclasses模块诞生了。

配合类型注解语法,我们可以轻松生成一个实现了__init____repr____cmp__等方法的dataclass:

from dataclasses import dataclass

@dataclass
class InventoryItem:
    '''Class for keeping track of an item in inventory.'''
    name: str
    unit_price: float
    quantity_on_hand: int = 0

    def total_cost(self) -> float:
        return self.unit_price * self.quantity_on_hand

同时使用dataclass也有一些好处,它比namedtuple更灵活。同时因为它是一个常规的类,所以你可以享受继承带来的便利。

dataclass的使用

我们分x步介绍dataclass的使用,首先是如何定义一个dataclass。

定义一个dataclass

dataclasses模块提供了一个装饰器帮助我们定义自己的数据类:

@dataclass
class Lang:
    """a dataclass that describes a programming language"""
    name: str = 'python'
    strong_type: bool = True
    static_type: bool = False
    age: int = 28

我们定义了一个描述某种程序语言特性的数据类——Lang,在接下来的例子中我们都会用到这个类。

在数据类被定义后,会根据给出的类型注解生成一个如下的初始函数:

def __init__(self, name: str='python',
            strong_type: bool=True,
            static_type: bool=False,
            age: int=28):
    self.name = name
    self.strong_type = strong_type
    self.static_type = static_type
    self.age = age

可以看到初始化操作都已经自动生成了,让我们试用一下:

>>> Lang()
Lang(name='python', strong_type=True, static_type=False, age=28)
>>> Lang('js', False, False, 23)
Lang(name='js', strong_type=False, static_type=False, age=23)
>>> Lang('js', False, False, 23) == Lang()
False
>>> Lang('python', True, False, 28) == Lang()
True

例子中可以看出__repr____eq__方法也已经为我们生成了,如果没有其他特殊要求的话这个dataclass已经具备了投入生产环境的能力,是不是很神奇?

深入dataclass装饰器

dataclass的魔力源泉都在dataclass这个装饰器中,如果想要完全掌控dataclass的话那么它是你必须了解的内容。

装饰器的原型如下:

dataclasses.dataclass(*, init=True, repr=True, eq=True, order=False, unsafe_hash=False, frozen=False)

dataclass装饰器将根据类属性生成数据类和数据类需要的方法。

我们的关注点集中在它的kwargs上:

key 含义
init 指定是否自动生成__init__,如果已经有定义同名方法则忽略这个值,也就是指定为True也不会自动生成
repr 同init,指定是否自动生成__repr__;自动生成的打印格式为class_name(arrt1:value1, attr2:value2, ...)
eq 同init,指定是否生成__eq__;自动生成的方法将按属性在类内定义时的顺序逐个比较,全部的值相同才会返回True
order 自动生成__lt____le____gt____ge__,比较方式与eq相同;如果order指定为True而eq指定为False,将引发ValueError;如果已经定义同名函数,将引发TypeError
unsafehash 如果是False,将根据eq和frozen参数来生成__hash__:
1. eq和frozen都为True,__hash__将会生成
2. eq为True而frozen为False,__hash__被设为None
3. eq为False,frozen为True,__hash__将使用超类(object)的同名属性(通常就是基于对象id的hash)
当设置为True时将会根据类属性自动生成__hash__,然而这是不安全的,因为这些属性是默认可变的,这会导致hash的不一致,所以除非能保证对象属性不可随意改变,否则应该谨慎地设置该参数为True
frozen 设为True时对field赋值将会引发错误,对象将是不可变的,如果已经定义了__setattr____delattr__将会引发TypeError

有默认值的属性必须定义在没有默认值的属性之后,和对kw参数的要求一样。

上面我们偶尔提到了field的概念,我们所说的数据类属性,数据属性实际上都是被field的对象,它代表着一个数据的实体和它的元信息,下面我们了解一下dataclasses.field

数据类的基石——dataclasses.field

先看下field的原型:

dataclasses.field(*, default=MISSING, default_factory=MISSING, repr=True, hash=None, init=True, compare=True, metadata=None)

通常我们无需直接使用,装饰器会根据我们给出的类型注解自动生成field,但有时候我们也需要定制这一过程,这时dataclasses.field就显得格外有用了。

default和default_factory参数将会影响默认值的产生,它们的默认值都是None,意思是调用时如果为指定则产生一个为None的值。其中default是field的默认值,而default_factory控制如何产生值,它接收一个无参数或者全是默认参数的callable对象,然后用调用这个对象获得field的初始值,之后再将default(如果值不是MISSING)复制给callable返回的这个对象。

举个例子,对于list,当复制它时只是复制了一份引用,所以像dataclass里那样直接复制给实例的做法的危险而错误的,为了保证使用list时的安全性,应该这样做:

@dataclass
class C:
    mylist: List[int] = field(default_factory=list)

当初始化C的实例时就会调用list()而不是直接复制一份list的引用:

>>> c1 = C()
>>> c1.mylist += [1,2,3]
>>> c1.mylist
[1, 2, 3]
>>> c2 = C()
>>> c2.mylist
[]

数据污染得到了避免。

init参数如果设置为False,表示不为这个field生成初始化操作,dataclass提供了hook——__post_init__供我们利用这一特性:

@dataclass
class C:
    a: int
    b: int
    c: int = field(init=False)

    def __post_init__(self):
        self.c = self.a + self.b

__post_init____init__后被调用,我们可以在这里初始化那些需要前置条件的field。

repr参数表示该field是否被包含进repr的输出,compare和hash参数表示field是否参与比较和计算hash值。metadata不被dataclass自身使用,通常让第三方组件从中获取某些元信息时才使用,所以我们不需要使用这一参数。

如果指定一个field的类型注解为dataclasses.InitVar,那么这个field将只会在初始化过程中(__init____post_init__)可以被使用,当初始化完成后访问该field会返回一个dataclasses.Field对象而不是field原本的值,也就是该field不再是一个可访问的数据对象。举个例子,比如一个由数据库对象,它只需要在初始化的过程中被访问:

@dataclass
class C:
    i: int
    j: int = None
    database: InitVar[DatabaseType] = None

    def __post_init__(self, database):
        if self.j is None and database is not None:
            self.j = database.lookup('j')

c = C(10, database=my_database)

这个例子中会返回c.ic.j的数据,但是不会返回c.database的。

一些常用函数

dataclasses模块中提供了一些常用函数供我们处理数据类。

使用dataclasses.asdictdataclasses.astuple我们可以把数据类实例中的数据转换成字典或者元组:

>>> from dataclasses import asdict, astuple
>>> asdict(Lang())
{'name': 'python', 'strong_type': True, 'static_type': False, 'age': 28}
>>> astuple(Lang())
('python', True, False, 28)

使用dataclasses.is_dataclass可以判断一个类或实例对象是否是数据类:

>>> from dataclasses import is_dataclass
>>> is_dataclass(Lang)
True
>>> is_dataclass(Lang())
True

dataclass继承

python3.7引入dataclass的一大原因就在于相比namedtuple,dataclass可以享受继承带来的便利。

dataclass装饰器会检查当前class的所有基类,如果发现一个dataclass,就会把它的字段按顺序添加进当前的class,随后再处理当前class的field。所有生成的方法也将按照这一过程处理,因此如果子类中的field与基类同名,那么子类将会无条件覆盖基类。子类将会根据所有的field重新生成一个构造函数,并在其中初始化基类。

看个例子:

@dataclass
class Python(Lang):
    tab_size: int = 4
    is_script: bool = True

>>> Python()
Python(name='python', strong_type=True, static_type=False, age=28, tab_size=4, is_script=True)

@dataclass
class Base:
    x: float = 25.0
    y: int = 0

@dataclass
class C(Base):
    z: int = 10
    x: int = 15

>>> C()
C(x=15, y=0, z=10)

Lang的field被Python继承了,而C中的x则覆盖了Base中的定义。

没错,数据类的继承就是这么简单。

总结

合理使用dataclass将会大大减轻开发中的负担,将我们从大量的重复劳动中解放出来,这既是dataclass的魅力,不过魅力的背后也总是有陷阱相伴,最后我想提几点注意事项:

  • dataclass通常情况下是unhashable的,因为默认生成的__hash__None,所以不能用来做字典的key,如果有这种需求,那么应该指定你的数据类为frozen dataclass
  • 小心当你定义了和dataclass生成的同名方法时会引发的问题
  • 当使用可变类型(如list)时,应该考虑使用fielddefault_factory
  • 数据类的属性都是公开的,如果你有属性只需要初始化时使用而不需要在其他时候被访问,请使用dataclasses.InitVar

只要避开这些陷阱,dataclass一定能成为提高生产力的利器。

参考

https://docs.python.org/3.7/library/dataclasses.html

https://www.python.org/dev/peps/pep-0557

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

Python3.7 dataclass使

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

Python3.7 dataclass使

本文将带你走进python3.7的新特性dataclass,通过本文你将学会dataclass的使用并避免踏入某些陷阱。 dataclass简介 dataclass的使用 定义一个dataclass
2023-01-30

Django2.0 Python3.7

注意目录位置  python3 manage.py runserver ip:portip:port可以不写默认的是本机IP 127.0.0.1 port 8000登录成功如下:打开浏览器输入 127.0.0.1:8000 显示Django
2023-01-30

python数据类(dataclass)的具体使用

本文主要介绍了python数据类(dataclass)的具体使用,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
2023-03-21

巡风 win7 python3.7安装使

巡风是一款适用于企业内网的漏洞快速应急、巡航扫描系统,只做初步探测,无攻击性行为。其主体分为两部分:网络资产识别引擎,漏洞检测引擎。网络资产识别引擎会通过用户配置的IP范围定期自动的进行端口探测(支持调用MASSCAN),并进行指纹识别,识
2023-01-31

ansible2.7 python3.7

./configure --prefix=/ansible/pythonmakemake install报错: ModuleNotFoundError: No module named '_ctypes'解决方法: 下载安装:libffi
2023-01-31

dataclass与objectclass函数如何在Kotlin中使用

这期内容当中小编将会给大家带来有关dataclass与objectclass函数如何在Kotlin中使用,文章内容丰富且以专业的角度为大家分析和叙述,阅读完这篇文章希望大家可以有所收获。Kotlin基础教程之dataclass,object
2023-05-31

python3.7安装cx_Oracle

操作系统: win7-32bitpython版本:3.7.0oracle版本:10.2.0// pip方式安装// 打开cmd输入如下命令pip install cx_Oracle自动下载并安装完成后,进入C:\Users\Administ
2023-01-31

tornado6与python3.7

__auth__ = "aleimu"__doc__ = "学习tornado6.0+ 版本与python3.7+"import timeimport asyncioimport tornado.genimport tornado.webi
2023-01-31

centos7 python3.7+vi

安装python3.7https://www.python.org/downloads/https://www.python.org/downloads/release/python-372/wget https://www.python.
2023-01-31

python3中@dataclass的实现示例

Python3中的@dataclass装饰器用于简化数据类的创建,通过自动生成必要的方法,如init、repr和eq,简化代码并提高可读性。它支持init、repr、eq、order、unsafe_hash和frozen等参数,提供各种自定义选项。尽管@dataclass易于使用,但其也仅适用于简单数据类,不能自定义特殊方法,因此可能不适合所有用例。
python3中@dataclass的实现示例
2024-04-02

python3.7 错误: Modul

原因及处理: 在使用python是经常会用到import一个第三方库,但是有时候会提示某个模块不存在,如Crypto 其实是因为Python3里面这个模块的名字变了,pip install pycrypto试试安装成功后,如果还是提示没有该
2023-01-31

Mac安装Python3.7

Python 目前有两个版本一个是 Python2,一个是Python3,当然我们在学习一门技术的时候,应该是开始学习比较新的,而且官方也是推荐大家使用Pyhton3,所以接下来我们学习的版本都是以 Python3 来开始的。Mac 中其实
2023-01-31

Centos7 安装Python3.7

# 更改yum源cd /etc/yum.repos.d mv CentOS-Base.repo CentOS-Base.repo.bakwget -O CentOS-Base.repo http://mirrors.aliyun.com/r
2023-01-31

python3.7——openssl升级

Python3.7使用的openssl为1.0.2版本或1.1以上的版本Centos .9安装openssl 1.1版本 [root@python3_7 soft]# mkdir –p /soft[root@python3_7 soft]#
2023-01-31

Win10 安装Python3.7

浏览器打开 https://www.python.org/等网页完全打开,鼠标放到Downloads上浏览器打开 https://www.python.org/ftp/python/3.7.2/右键-我的电脑-属性重新打开一个
2023-01-31

Centos安装Python3.7

yum install libffi-devel gcc zlib* -ywget https://www.python.org/ftp/python/3.7.0/Python-3.7.0.tgz && tar -zxf Python-3.
2023-01-31

python3.6替换python3.7

使用低版本的python替换高版本的python只需要把环境变量中PATH的第一个python的路径替换成低版本的python的路径就行了。在编译python脚本的时候电脑就是使用第一个找到的python路径里的那个版本具体的方式是:我的电
2023-01-31

Linux安装Python3.7

0.下载安装包https://www.python.org/downloads/release/python-370/1.安装3.7之前要先安装一些依赖包    sudo apt-get update    sudo apt-get upg
2023-01-31

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录