[Python] 3.7中的dataclasses

简介:

这个dataclasses是当做装饰器来用,作用是在我们定义数据class对象时减少我们的代码量。

文章主要是用IDE写的,还请见谅。

 

正文:

from dataclasses import dataclass


#带上这个装饰器帽子,相当于它的init,repr,eq等双下划线方法都自动帮我们创建
@dataclass(init=True, repr=True, eq=True, order=True,unsafe_hash=False, frozen=False)
class Point:
    x: float
    __y: float #外部不可访问和更改
    z: float = 0.0
    # def __repr__(self):  #你也可以自己重写魔术方法,它将是最终生效的那个
    #     return "test"

p = Point(1.1,2.2) #加了装饰器可以直接进行赋值使用
p.__y = 111 #无法修改
print(p) #Point(x=1.1, _Point__y=2.2, z=0.0)
'''
戴帽子的时候也可以这样写:
@dataclass(init=True, repr=True, eq=True, order=False, unsafe_hash=False, frozen=False)
是的,你可以决定哪些魔术方法需要装饰器帮你自动添加到class中,注意它们的默认值。
init,repr这两个就不说了,__eq__这个方法:
它将class当做一个填充有字段的元组来比较是否相等,而且要求字段名,值,顺序,类型全部一致才算相等。
'''
p1 = Point(1.1,2.2)
p2 = Point(z=2.2,x=1.1,_Point__y=0)  #改变了形参位置
print(p==p1, p==p2) #true false

'''
order=True的话,那么__lt__,__le__,__gt__,ge__也就是<,<=,>,>=这些魔术方法都会生成到你的class中
#如果False,则定义的class不支持比较,会抛异常,除了==
默认的比较规则貌似是只比较第一个参数,你最好自己重写这些方法
'''
@dataclass(order=True)
class Point_1:
    x: float
    y: int
p3=Point_1(0.0, 1)
p4=Point_1(0.1, 0)
print(p3<p4) #true

'''
frozen=True的话,class的实例不支持修改,即instance.field=xxx 都是不支持的
'''
@dataclass(frozen=True)
class Point_2:
    x: float
    y: int
    z: dict
    # def __setattr__(self, key, value): #若frozen=true,连这个setattr方法都不允许定义(getattr也不准,参照https://www.python.org/dev/peps/pep-0557/#specification)
    #     self.z[key] = value
    def __getattr__(self, item): #不过这里并没有抛出异常
        return self.item
    # def __delattr__(self, item): #同样,它也不给定义
    #     del self.y

p3=Point_2(0.0, 1, {})
# p3.y = 1 #dataclasses.FrozenInstanceError: cannot assign to field 'y'
print(p3.z) #居然是可以访问的
'''
frozen: If true (the default is False), assigning to fields will generate an exception. 
This emulates read-only frozen instances. If either __getattr__ or __setattr__ is defined in the class, then ValueError is raised
原话说的是模仿一个 只读的实例,__getattr__和__setattr__都不允许自定义,否则抛异常。
个人认为__setattr__不允许自定义是ok的,__getattr__不允许那还怎么读呢,所以这里应该是表述有问题。
'''

'''
unsafe_hash默认是false,但它会根据eq和frozen参数来进行设置
若eq和frozen都是true,那么__hash__方法将会添加到class中
若eq=true,frozen=false,那么__hash__=None, 且标记class为unhashable的类
若eq=false,将保持原来的__hash__方法,意思是使用class父类的哈希方法,python3中默认类都是继承自object类(或者继承了别的类)。
'''
@dataclass(frozen=True)
class Point_3:
    x: float

p4 = Point_3(1)
print(p4.__hash__) #<bound method __hash__ of Point_3(x=1)> 标明此类是有hash方法的
print(p4.__hash__()) # 3430019387558  调用其hash方法,等效于hash(p4)
print(hash(p4) == p4.__hash__())

@dataclass(frozen=False,eq=True) #这个时候__hash__=None
class Point_4:
    x: float
p5 = Point_4(1)
print(p5.__hash__) #None
# print(p5.__hash__())  #'NoneType' object is not callable

'''
##关于field()方法##
有时候在数据类中我们需要给一些字段附加一些额外的信息,
如a这个字段我要定死,不给它走init,在repr中也不希望被显示出来,还不希望拿来比较
'''

from dataclasses import field
@dataclass(unsafe_hash=True) #强制生成__hash__方法
class Point_5:
    x: float
    y: int = field(default=10,init=False,repr=False)
    z: str = field(default="", compare=False) #比较时忽略此字段
    f: str = field(default="", hash=False) #true的话,hash后的结果是不一样的

p6 = Point_5(x=1, z="A") #不再允许被设置
print(p6.y) #10 仍然可以访问
print(p6) #Point_5(x=1) 显示的查看对象也看不到y的值了

p7 = Point_5(x=1, z="B")
print(p6==p7) #true  z被忽略了,只比较了x
print(hash(p7))

#使用default_factory参数来为字段设置默认值,他必须是一个可调用的对象,比如func,class
#要注意它和default是不相容的,有你没我,定义时只能使用两者中一个参数
def generate_x():
    return 1
@dataclass
class Point_6:
    x: float = field(default_factory=generate_x) #
    y: float = field(default_factory=dict) #list, str, int...
p8 = Point_6()
print(p8)  #Point_6(x=1)

如上已经介绍了大部分dataclasses库的用法,更多关于它的使用参考PEP-0557

python3.7的更新参考Whatsnewin3.7

  • 3
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值