前言:
Python是面向对象的语言,一般情况下使用面向对象编程会使得开发效率更高,软件质量更好,并且代码更易于扩展,可读性和可维护性也更高。但是如果在一个较大的项目中,如果实体类非常多并且有非常复杂的属性,你就会逐渐觉得Python的类写起来是真・“累”。为什么这样说,看下下面这个Box
类,属性有长(length
)、宽(width
)、高(hight
):
class Box: def __init__(self, length, width, hight): self.length = length self.width = width self.hight = hight
这样倒没有什么问题,而且是符合Python
规范的写法,初始化函数内每一个参数都需要用self.xxx = xxx
进行赋值,参数少了还好,但是如果参数过多了,只是参数赋值操作都够写一会的了,如果一个项目中类也有很多,那就真的要麻木了。
而且我们知道,在Python
中,想要自定义对象本身的打印输出结果的时候,需要在它的类中实现__repr__()
方法,例如:
def __repr__(self): return '{}(length={}, width={}, hight={})'.format( self.__class__.__name__, self.length, self.width, self.hight)
实现了__repr__()
方法,当我们打印对象本身的时候,才会输出我们自定义的字符。
box = Box(20, 15, 15) print(box) # 结果输出为 Box(length=20, width=15, hight=15)
但是有时会因为麻烦,我们不愿意去实现__repr__()
方法,但是不实现打印结果又不友好,就陷入了纠结之中。
如果我么想要实现对象比较,有时候需要判断2个对象是否相等或者比较大小,就要实现__eq__()
、 __lt__()
、__gt__()
等各种方法来实现对象之间的比较,例如:
def __eq__(self, other): if not isinstance(other, self.__class__): return NotImplemented return (self.length, self.width, self.hight) == ( other.length, other.width, other.hight)
这样我们又需要实现这几个用于比较的方法。 比如说我们已经实现了上面说过的所有方法,然后又突然添加一个属性结实度hardness,那么整个类的方法都需要修改,这是非常折磨人的。 那么有没有一种方法,可以在创建类的时候自动添加上类似于上面提到的这些东西,答案是有的,那就是我们接下来要介绍的attrs
模块,它可以帮助我们很方便的定义类。
1、attrs的使用
我们可以使用pip install attrs
进行安装。
然后将上面的代码改造一下:
from attr import attrs, attrib @attrs class Box: length = attrib(type=int, default=0) width = attrib(type=int, default=0) hight = attrib(type=int, default=0) box1 = Box(20, 15, 15) print(box1) box2 = Box(30, 20, 20) print(box2 == box1) print(box2 > box1)
用模块内的attrs
修饰了Box类,再使用attrib
定义所有的属性,同时指定了属性的类型和默认值。而且我们没有实现任何一个上面所提到的方法,但是确实实现了所有的功能。 现在如果我们添加一个属性颜色color
,这个属性不参与对象的比较,但是打印的时候要输出,添加一个属性结实度hardness
,这个属性参与对象的比较,但是打印对象的时候不输出,就非常简单了:
from attr import attrs, attrib @attrs class Box: length = attrib(type=int, default=0) width = attrib(type=int, default=0) hight = attrib(type=int, default=0) color = attrib(repr=True, cmp=False, default=(0, 0, 0)) hardness = attrib(repr=False, cmp=True, default=0) box1 = Box(20, 15, 15, (255, 255, 255), 80) print("box1:", box1) box2 = Box(20, 15, 15, (255, 255, 0), 100) print("box2:", box2) print(box2 == box1) print(box2 > box1)
执行结果为:
也就是说,如果我们用了attrs库的话,会让类的定义变得高效简洁,就不需要再写哪些冗余又复杂的代码了。 关于attrib()
,接收以下参数:
-
default
:属性的默认值,如果没有传入初始化数据,那么就会使用默认值 -
validator
:验证器,检查传入的参数是否合法 -
repr
:是否参与对象打印时的输出 -
cmp
:是否参与对象比较 -
hash
:是否进行去重 -
init
:是否参与初始化,如果为False,那么这个参数不能当做类的初始化参数,默认是True -
metadata
:元数据,只读性的附加数据 -
type
:类型,比如 int、str 等各种类型,默认为 None -
converter
:转换器,进行一些值的处理和转换器,增加容错性 -
kw_only
:是否为强制关键字参数,默认为 False
这里我们只重点说一下验证器和转换器,其他的参数都很好理解。
2、验证器
有时候在设置一个属性的时候必须要满足某个条件,比如上面的颜色color
属性,我们使用的是RGB三原色方式,例如黑色是(255,255,255),对于这种情况,我们就需要验证属性是否合法。
例如:
def color_is_valid(instance, attr, value): if not isinstance(value, set): raise ValueError(f"参数{attr.name}:{value}不合法!") for i in value: if not 0 <= i<= 255: raise ValueError(f"参数{attr.name}:{value}不合法!") @attrs class Box: length = attrib(type=int, default=0) width = attrib(type=int, default=0) hight = attrib(type=int, default=0) color = attrib(repr=True, cmp=False, validator=color_is_valid, default=(0, 0, 0)) hardness = attrib(repr=False, cmp=True, default=0) box1 = Box(20, 15, 15, (255, 255, 260), 80)
执行结果为:
上述代码中定义了一个验证器color_is_valid()
方法来验证颜色color
是否合法,不合法时就会抛异常。
验证器方法接收三个参数:
-
instance
:类对象 -
attr
:属性名 -
value
:属性值
而且attrs
模块也提供了许多内置验证器,这里就不做赘述了。
3、转换器
转换器主要做一些值的处理和转换,增加类的容错性,比如一个属性接收的是int类型,我们想要的是传入了数字字符串也不会报错,那我们就可以增加转换器,将字符串自动转为数字,例如:
def to_int(value): try: return int(value) except: return None @attrs class Box: length = attrib(type=int, default=0, converter=to_int) width = attrib(type=int, default=0, converter=to_int) hight = attrib(type=int, default=0) color = attrib(repr=True, cmp=False, default=(0, 0, 0)) hardness = attrib(repr=False, cmp=True, default=0) box1 = Box("20", "15", 15, (255, 255, 255), 80) print("box1:", box1) box2 = Box("2a", 15, 15, (255, 255, 0), 100) print("box2:", box2)
上面定义了一个方法to_int()
,可以将值转化为数字类型,转换异常就返回None
,这样容错性非常高了。
到此这篇关于Python attrs提高面向对象编程效率详细的文章就介绍到这了,更多相关Python attrs提高面向对象编程效率内容请搜索服务器之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持服务器之家!
原文链接:https://juejin.cn/post/7000533949113958408