python vector 初始化_Python中的内置数据类

前言

Python3.7及以上版本中,增加了一个dataclasses标准库,它主要用来做数据的容器,同时它还为开发人员预制了标准方法,并简化了类的创建过程,在这篇文章中,我们来研究一下这个标准库。

我们的第一个数据类

让我们先来创建一个数据类,它是空间坐标系中点的三维坐标(x,y,z),这可以直接利用dataclasses中的@dataclass描述符来实现:
from dataclasses import dataclass@dataclassclass Coordinate:   x: int   y: int   z: int
请注意上述类中的写法,如果有熟悉 go 语言的同学应该会对这种写法不陌生,但在 Python 中,这种写法显得比较另类,因为 Python 本身是动态语言,其变量的类型可以在程序执行的过程中发生变化,但这个类里面的写法却是将每个变量的数据类型进行了限定,这一点是与众不同的,从另一方面来看,各种语言的融合也是在悄无声息中进行,所谓取长补短吧。 默认情况下,数据类已经帮我们在上述Coordinate类中实现了__init____repr____eq__等方法,因此我们可以直接使用这些方法:
a = Coordinate(3,5,4)print(a)>>> 输出:Coordinate(x=3, y=5, z=4)>>> repr(a)'Coordinate(x=3, y=5, z=4)'
为数据类中的成员 设置默认值 比如我们来定义一个CircleArea类,其中有个属性是用来计算圆的面积,代码如下:
@dataclassclass CircleArea:   r: int   pi: float=3.14      @property   def area(self):       return self.pi * (self.r ** 2)   a = CircleArea(2)a>>> 输出:CircleArea(r=2, pi=3.14)>>> 输出:12.56
上述代码中,我们为类 CircleArea 中的成员 pi 设置了默认值。

类中成员值的变与不变

通常情况下,类中成员值是可以被改变的,比如上面定义的CircleArea
a = CircleArea(2)a.r = 5a.pi = 3a.area>>> 输出:75
上述代码演示了类中成员值可变的问题,可有时候我们并不想一个对象被创立后,其成员值还变化,这时候就要用到 dataclass 的一个参数 frozen ,将其设置为 True 即可:
@dataclass(frozen=True)class CircleArea:    r: int    pi: float=3.14        @property    def area(self):        return self.pi * (self.r ** 2)    a = CircleArea(2)a.r = 5

40c58323bdfc29705c01695e7691377a.png

从上述解释器的报错信息可以看出,设定 frozen=True 以后,类实例的创建只能在其初始化时进行,之后的修改都是不被允许的。

数据类实例的比较

在数学中,比较大小是最常见的操作,比如我们定义一个向量类,由它产生的实例都是向量,这时如果想比较向量大小的话,一般要先给出定义,比如有两个向量A(x1,y1)B(x2,y2),如果x1>x2,那么我们就说向量A>B,如果x1==x2,那么当y1>y2时我们就说A>B,这样的比较大小逻辑在dataclasses标准库中已经帮我们实现了,唯一我们要做的是在创建用@dataclass修饰的类时,将其参数order设置为True即可:
@dataclass(order=True)class Vector:    x : int    y : int        v1 = Vector(4,9)v2 = Vector(3,10)print(v1 > v2)>>> 输出:True
上面代码的结果判定为 True ,这说明根据类自身的定义可知 v1>v2 ,可是如果我们不想用上述比较向量大小的定义,想用向量本身的大小,即用向量中各分量平方和的平方根来比较大小时该如何做呢? 此时要用到一个 dataclass 中内置的 __post_init__ 来定义,同时所定义的大小变量要用 field 来限定,具体代码如下:
from dataclasses import dataclass, field@dataclass(order=True)class Vector:    vectorlen : float = field(init=False)    x : int    y : int            def __post_init__(self):        self.vectorlen = (self.x ** 2 + self.y ** 2) ** 0.5        v1 = Vector(9,12)v2 = Vector(5,12)print(v1)print(v2)print(v1>v2)>>> 输出:Vector(vectorlen=15.0, x=9, y=12)Vector(vectorlen=13.0, x=5, y=12)True
将类实例转换为字典或元组 我们可以直接将由@dataclass修饰的类转换为一个字典或一个元组,所用到的函数也很简单,分别是:asdictastuple
from dataclasses import dataclass, asdict, astuple@dataclass()class Vector:    x : int    y : int    z : int        v = Vector(2,4,9)print(asdict(v))print(astuple(v))>>> 输出:{'x': 2, 'y': 4, 'z': 9}(2, 4, 9)
关于类的继承 用@dataclass修饰的类也同样具备普通继承的属性,比如:
@dataclassclass Person:    name : str    sex  : str        @dataclassclass Programmer(Person):    lang : str        p1 = Programmer("张三", "男", "Python")print(p1)>>> 输出:Programmer(name='张三', sex='男', lang='Python')
但是如果我们提前给某个父类中的成员设置默认值后,再调用子类创建实例就会报错,比如:
@dataclassclass Person:    name : str    sex  : str = "男"        @dataclassclass Programmer(Person):    lang : str        p1 = Programmer("张三", "男", "Python")print(p1)

a1143043b8683f6a9e6d082fbb6e415f.png

以上两段代码唯一不同的地方,在于第二段代码中对父类Person中的成员sex提前指定了默认值,这就导致了错误,这是因为:当我们在调用子类实例化对象时,它事实上是这样调用初始化函数的:
def __init__(name:str, sex:str="男", lang:str):    ...
从这个函数形式上来看,第二个参数给出了默认值,但第三个参数却没有,这样不符合函数的形式化定义,因此,在父类中指定了某个成员为默认值后,子类中同样要为所有成员指定默认值,修改代码如下:
@dataclassclass Person:    name : str    sex  : str = "男"        @dataclassclass Programmer(Person):    lang : str = ""        p1 = Programmer("张三", "男", "Python")print(p1)>>> 输出:Programmer(name='张三', sex='男', lang='Python')
小结 这一篇文章中介绍了Python的标准库dataclasses,它内置了一些标准化的方式,对于数学方面的处理显得很方便,现在此简单介绍,以便于备忘和有需要的同学借鉴。
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值