Python attrs提高面向对象编程效率详细
前言:
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,那么这个参数不能当做类的初始化参数,默认是Truemetadata
:元数据,只读性的附加数据type
:类型,比如 int、str 等各种类型,默认为 Noneconverter
:转换器,进行一些值的处理和转换器,增加容错性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提高面向对象编程效率内容请搜索编程宝库以前的文章,希望大家多多支持编程宝库!
python网络爬虫之模拟登录 自动获取cookie值 验证码识别的具体实现: 1、爬取网页分析爬取的目标网址为:https://www.gushiwen.cn/在登陆界面需要做的工作有,获取验证码图片,并识别该验证码,才能实现登 ...