前言

之前有写过一篇python元类的笔记,元类主要作用就是在要创建的类中使用参数metaclass=YourMetaclass调用自定义的元类,这样就可以为所有调用了这个元类的类添加相同的属性了。

python数据类初识

用docker拉个python:3.7的镜像作为实验环境

使用dataclass装饰器创建数据类

>>> from dataclasses import dataclass

>>> @dataclass

... class DataClassTest:

... first_name: str

... last_name: str

...

>>> p = DataClassTest('vickey', 'wu')

>>> p.first_name

'vickey'

>>> p.last_name

'wu'

>>> p

DataClassTest(first_name='vickey', last_name='wu')

>>> p == DataClassTest('vickey', 'wu')

True

>>> p.first_name = 'wiki'

>>> p

DataClassTest(first_name='wiki', last_name='wu')

从上面例子可以看到,如果使用dataclass装饰器来定义数据类,则必须声明参数类型,数据类默认可以修改参数的值类型,如果不希望更改则使用@dataclass(frozen=True)即可,这样上面的 参数值就不可更改了,更改会报错dataclasses.FrozenInstanceError: cannot assign to field 'first_name'。

当不确定参数到底用哪种类型,或可以是多种类型时则可以用下面的Any来声明

>>> from dataclasses import dataclass

>>> from typing import Any

>>> @dataclass

... class W:

... n:Any

... v: float = 18

...

>>> w = W('vickey')

>>> w

W(n='vickey', v=18)

>>> w = W(19)

>>> w

W(n=19, v=18)

不使用dataclass装饰器的普通类

>>> class RegularClassTest:

... def __init__(self, first_name, last_name):

... self.first_name = first_name

... self.last_name = last_name

...

>>> pp = RegularClassTest('vickey', 'wu')

>>> pp.first_name

'vickey'

>>> pp.last_name

'wu'

>>> pp

>>> pp == RegularClassTest('vickey', 'wu')

False

从1和2两个例子对比可以看出,使用@dataclass后有几个优势(不限于此):

无需定义__init__函数,只需定义参数及参数类型即可。

打印出来的对象描述信息更清晰了。而未使用dataclass的类需要再添加__repr__函数显示才友好。(看下面的例子)

实例化后的实例可以用==判断出是否与类实例相等,而未使用dataclass的类需要再添加__eq__函数才能判断。(看下面的例子)

3 不使用dataclass装饰器实现数据类相同功能

>>> class RegularClassTest2:

... def __init__(self, first_name, last_name):

... self.first_name = first_name

... self.last_name = last_name

... def __repr__(self):

... return (f'{self.__class__.__name__}'

... f'(first_name={self.first_name!r}, last_name={self.last_name!r})')

... def __eq__(self, other):

... if other.__class__ is not self.__class__:

... return NotImplemented

... return (self.first_name, self.last_name) == (other.first_name, other.last_name)

...

>>> r = RegularClassTest2('2', '1')

>>> r

RegularCard(first_name='2', last_name='1')

>>> r == RegularClassTest2('2', '1')

True

>>>

通过在普通类中添加__repr__和__eq__就可以具有上面提到的数据类的第2,3个优势,但还是需要__init__函数。虽然上面提到不使用dataclass也可以达到部分效果,参考文章作者也说明了各自的好处与不足,感兴趣的童鞋查看原文,这里就不记录了。

数据类参数调用函数赋值

from dataclasses import dataclass, field

from typing import List

# 数据类rank参数为牌大小,suit为花色

@dataclass

class PlayingCard:

rank: str

suit: str

# 生成13牌的4种花色

RANKS = '2 3 4 5 6 7 8 9 10 J Q K A'.split()

SUITS = '♣ ♢ ♡ ♠'.split()

def make_french_deck():

print([PlayingCard(r, s) for s in SUITS for r in RANKS])

print('################## list generated by fuction make_french_deck')

return [PlayingCard(r, s) for s in SUITS for r in RANKS]

# 参考源码typing.List

# List(yourclass):https://docs.python.org/3/library/typing.html#typing.ForwardRef

# 使用field的default_factory调用参数名为make_french_deck的函数,这个函数会生成一个list,然后赋值参数cards

@dataclass

class Deck:

cards: List[PlayingCard] = field(default_factory=make_french_deck)

print('################# called class Deck with para cards')

print(Deck())

output

################# called class Deck with para cards

[PlayingCard(rank='2', suit='♣'), PlayingCard(rank='3', suit='♣'), PlayingCard(rank='4', suit='♣'), PlayingCard(rank='5', suit='♣'), PlayingCard(rank='6', suit='♣'), PlayingCard(rank='7', suit='♣'), PlayingCard(rank='8', suit='♣'), PlayingCard(rank='9', suit='♣'), PlayingCard(rank='10', suit='♣'), PlayingCard(rank='J', suit='♣'), PlayingCard(rank='Q', suit='♣'), PlayingCard(rank='K', suit='♣'), PlayingCard(rank='A', suit='♣'), PlayingCard(rank='2', suit='♢'), PlayingCard(rank='3', suit='♢'), PlayingCard(rank='4', suit='♢'), PlayingCard(rank='5', suit='♢'), PlayingCard(rank='6', suit='♢'), PlayingCard(rank='7', suit='♢'), PlayingCard(rank='8', suit='♢'), PlayingCard(rank='9', suit='♢'), PlayingCard(rank='10', suit='♢'), PlayingCard(rank='J', suit='♢'), PlayingCard(rank='Q', suit='♢'), PlayingCard(rank='K', suit='♢'), PlayingCard(rank='A', suit='♢'), PlayingCard(rank='2', suit='♡'), PlayingCard(rank='3', suit='♡'), PlayingCard(rank='4', suit='♡'), PlayingCard(rank='5', suit='♡'), PlayingCard(rank='6', suit='♡'), PlayingCard(rank='7', suit='♡'), PlayingCard(rank='8', suit='♡'), PlayingCard(rank='9', suit='♡'), PlayingCard(rank='10', suit='♡'), PlayingCard(rank='J', suit='♡'), PlayingCard(rank='Q', suit='♡'), PlayingCard(rank='K', suit='♡'), PlayingCard(rank='A', suit='♡'), PlayingCard(rank='2', suit='♠'), PlayingCard(rank='3', suit='♠'), PlayingCard(rank='4', suit='♠'), PlayingCard(rank='5', suit='♠'), PlayingCard(rank='6', suit='♠'), PlayingCard(rank='7', suit='♠'), PlayingCard(rank='8', suit='♠'), PlayingCard(rank='9', suit='♠'), PlayingCard(rank='10', suit='♠'), PlayingCard(rank='J', suit='♠'), PlayingCard(rank='Q', suit='♠'), PlayingCard(rank='K', suit='♠'), PlayingCard(rank='A', suit='♠')]

################## list generated by fuction make_french_deck

Deck(cards=[PlayingCard(rank='2', suit='♣'), PlayingCard(rank='3', suit='♣'), PlayingCard(rank='4', suit='♣'), PlayingCard(rank='5', suit='♣'), PlayingCard(rank='6', suit='♣'), PlayingCard(rank='7', suit='♣'), PlayingCard(rank='8', suit='♣'), PlayingCard(rank='9', suit='♣'), PlayingCard(rank='10', suit='♣'), PlayingCard(rank='J', suit='♣'), PlayingCard(rank='Q', suit='♣'), PlayingCard(rank='K', suit='♣'), PlayingCard(rank='A', suit='♣'), PlayingCard(rank='2', suit='♢'), PlayingCard(rank='3', suit='♢'), PlayingCard(rank='4', suit='♢'), PlayingCard(rank='5', suit='♢'), PlayingCard(rank='6', suit='♢'), PlayingCard(rank='7', suit='♢'), PlayingCard(rank='8', suit='♢'), PlayingCard(rank='9', suit='♢'), PlayingCard(rank='10', suit='♢'), PlayingCard(rank='J', suit='♢'), PlayingCard(rank='Q', suit='♢'), PlayingCard(rank='K', suit='♢'), PlayingCard(rank='A', suit='♢'), PlayingCard(rank='2', suit='♡'), PlayingCard(rank='3', suit='♡'), PlayingCard(rank='4', suit='♡'), PlayingCard(rank='5', suit='♡'), PlayingCard(rank='6', suit='♡'), PlayingCard(rank='7', suit='♡'), PlayingCard(rank='8', suit='♡'), PlayingCard(rank='9', suit='♡'), PlayingCard(rank='10', suit='♡'), PlayingCard(rank='J', suit='♡'), PlayingCard(rank='Q', suit='♡'), PlayingCard(rank='K', suit='♡'), PlayingCard(rank='A', suit='♡'), PlayingCard(rank='2', suit='♠'), PlayingCard(rank='3', suit='♠'), PlayingCard(rank='4', suit='♠'), PlayingCard(rank='5', suit='♠'), PlayingCard(rank='6', suit='♠'), PlayingCard(rank='7', suit='♠'), PlayingCard(rank='8', suit='♠'), PlayingCard(rank='9', suit='♠'), PlayingCard(rank='10', suit='♠'), PlayingCard(rank='J', suit='♠'), PlayingCard(rank='Q', suit='♠'), PlayingCard(rank='K', suit='♠'), PlayingCard(rank='A', suit='♠')])

上面的例子是类Deck调用了类外的一个函数make_french_deck来生成一个类Deck的列表类型参数cards,这个列表由传入类PlayingCard不同参数rank和suit而生成的类PlayingCard调用列表。这样就生成了13牌的4种花色的所有值。

数据类的继承

from dataclasses import dataclass

@dataclass

class Position:

name: str

lon: float = 0.0

lat: float = 0.0

@dataclass

class Capital(Position):

# 因为父类参数有默认值,所以子类的参数必须定义默认值,否则报错

# country: str

country: str = 'Unknown'

# 可以在子类重新定义父类的参数默认值

lat: float = 40.0

如果父类参数有默认值,子类的所有参数必须定义默认值,否则报错:TypeError: non-default argument 'country' follows default argument。报错原因相当于在子类初始化时def __init__(name: str, lon: float = 0.0, lat: float = 0.0, country: str):非默认参数没有在默认参数前面,因为python规定非默认参数必须在默认参数前面。

参数的顺序按照父类顺序,然后子类参数顺序。

总结

数据类是Python3.7的新特性之一。使用数据类就不必编写样板代码来为对象获得适当的初始化__init__,表示__repr__,和比较__eq__。

数据类参数必须声明参数类型,参数可以使用函数赋值。

在继承时如果父类参数有定义默认值,则子类参数必须也要定义默认值,继承后的参数顺序为父类参数,然后到子类参数。

除此之外,数据类和普通类区别不大,数据类定义参数后像普通类一样定义实例方法,一样调用。

公众号往期文章

python内置装饰器

python装饰器

scrapy-redis debug视频

scrapy-redis源码浅析

scrapy过滤重复数据和增量爬取

redis基础笔记

scrapy电影天堂实战(二)创建爬虫项目

scrapy电影天堂实战(一)创建数据库

scrapy基础笔记

在docker镜像中加入环境变量

笔记 | mongodb 入门操作

笔记 | python元类

笔记 | python2和python3使用super()

那些你在python3中可能没用到但应该用的东西

superset docker 部署

开机启动容器里面的程序

博客 | 三步部署hitchhiker-api

python 数据类_python数据类相关推荐

  1. python客户画像_Python数据分析学习笔记05:用户画像

    Python数据分析学习笔记05:用户画像 一.用户画像 用户画像是指根据用户的属性.用户偏好.生活习惯.用户行为等信息而抽象出来的标签化用户模型.通俗说就是给用户打标签,而标签是通过对用户信息分析而 ...

  2. python元类_Python元类

    python元类 Welcome to today's tutorial on python metaclass. We all know that python is an object orien ...

  3. python画板颜色_Python数据可视化:Seaborn(二):色板

    在进行数据可视化处理的时候,常常会涉及到多个类的数据,有些时候默认的颜色并不是我们想要的,这时候,如果我们想要一些我们喜欢的颜色,就需要调整色板,下面我们就来介绍一下Seaborn的色板调整. 首先依 ...

  4. python matplotlib画数据分布图_Python数据可视化之matplotlib

    数据可视化能让人们更直观的传递数据所要表达的信息.Python 中有两个专用于可视化的库,matplotlib 和 seaborn ,本文将介绍matplotlib. Matplotlib:基于Pyt ...

  5. python数据输出_python数据输出

    下面的是我的code, 但是最后的结果全部都是others,有哪位大神能帮忙看产生输出的最简单方法是使用print语句,可以通过用逗号分隔零个或多个表达式.这个函数传递表达式转换为一个字符串,如下结果 ...

  6. python交互式数据可视化_python数据可视化工具

    熟知python的人都知道,python上常用的一款数据可视化工具是Matplotlib,但是Matplotlib是静态的.那么,Python中除了matplotlib外,还有哪些数据可视化工具呢?其 ...

  7. python经典类新式类_Python新式类与经典类(旧式类)的区别

    看写poc的时候看到的,思考了半天,现在解决了 转载自http://blog.csdn.net/zimou5581/article/details/53053775 Python中类分两种:旧式类和新 ...

  8. python面向对象类_python:面向对象(类)

    #!usr/bin/env python # -*- coding:utf-8 -*- __author__ = "Samson" ###类变量与实例变量 class Role: ...

  9. python 新式类和旧式类_python新式类和旧式类区别

    python的新式类是2.2版本引进来的,我们可以将之前的类叫做经典类或者旧式类. 为什么要在2.2中引进new style class呢?官方给的解释是: 为了统一类(class)和类型(type) ...

最新文章

  1. 利用 PortableBasemapServer 发布地图服务
  2. WPF纯手工两步打造图片切割工具(一)
  3. 关闭oracle自动统计,禁用oracle 11g 的统计数据自动功能
  4. 【H2 Database】安装
  5. 前端学习(2875):原生js模块化+入口模块和子类的编写
  6. 案例:ORA-04031 12.1.0.2 on exadata x7
  7. 玩个锤子,李飞飞夫妇团队的最新研究
  8. 这个严重漏洞可被滥用于破坏交通信号灯系统
  9. MXRuntimeUtils,替代 [NSObject performSelector object object ]的工具
  10. 11-411/611NLP Lecture 4.Words and Morphology
  11. jar包转换为exe可执行文件
  12. Postman-汉化插件
  13. 怎么留住好员工来实现企业优势
  14. 让Mac文本编辑器成为HTML编辑器
  15. CorAl – Are the point clouds Correctly Aligned?
  16. 使用mysql解决Excel换行统计问题
  17. “开宝五子棋陪练”-首款开放智能的五子棋习题练习安卓应用
  18. java动态多态性是通过什么实现的_11.java实现动态多态性是通过()实现的 答案:覆盖...
  19. IEC60958和IEC61937
  20. 第一次如何上线项目(一)

热门文章

  1. Oracle中一般游标与REF游标的区别
  2. LabVIEW I/O服务器创建时的相关问题汇总
  3. CSS——FC(BFC/IFC/FFC/GFC)超详细版+原理案例分析
  4. java中对date的一些处理以及获取date
  5. linux 减小根分区大小_减小linux下根分区
  6. App-V轻量级应用程序虚拟化之三客户端测试
  7. Jquery Mobile 画面导航栏共用的实现方法
  8. OS: 读者写者问题(写者优先+LINUX+多线程+互斥量+代码)(转)
  9. XHTML的使用规范
  10. VMware中的三种网络模式-----Host-only模式