Python attrs提高面向对象编程效率详细

 更新时间:2021年09月27日 08:57:04   作者:tigeriaf  
Python是面向对象的语言,一般情况下使用面向对象编程会使得开发效率更高,软件质量更好,并且代码更易于扩展,可读性和可维护性也更高,但是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,那么这个参数不能当做类的初始化参数,默认是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提高面向对象编程效率内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • pyspark 随机森林的实现

    pyspark 随机森林的实现

    这篇文章主要介绍了pyspark 随机森林的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-04-04
  • Python求解排列中的逆序数个数实例

    Python求解排列中的逆序数个数实例

    这篇文章主要介绍了Python求解排列中的逆序数个数实例,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2020-05-05
  • python中的不可变数据类型与可变数据类型详解

    python中的不可变数据类型与可变数据类型详解

    探寻python的数据类型是否可变,也可以更好的理解python对内存的使用情况,下面这篇文章主要给大家介绍了关于python中不可变数据类型与可变数据类型的相关资料,文中通过示例代码介绍的非常详细,需要的朋友可以参考下
    2018-09-09
  • python logging.basicConfig不生效的原因及解决

    python logging.basicConfig不生效的原因及解决

    今天小编就为大家分享一篇python logging.basicConfig不生效的原因及解决,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2020-02-02
  • 详解Python中的__new__()方法的使用

    详解Python中的__new__()方法的使用

    本文主要介绍了Python中的__new__()方法的使用的基本知识,本文中给出了基于Python2.x的代码实例,需要的朋友可以参考一下
    2015-04-04
  • Pytorch四维Tensor转图片并保存方式(维度顺序调整)

    Pytorch四维Tensor转图片并保存方式(维度顺序调整)

    这篇文章主要介绍了Pytorch四维Tensor转图片并保存方式(维度顺序调整),具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-12-12
  • python求众数问题实例

    python求众数问题实例

    这篇文章主要介绍了python求众数问题实例,包括文件的读写、字典的运用及数值的计算等技巧,需要的朋友可以参考下
    2014-09-09
  • Python 实现选择排序的算法步骤

    Python 实现选择排序的算法步骤

    下面小编就为大家分享一篇Python 实现选择排序的算法步骤,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2018-04-04
  • python GUI库图形界面开发之PyQt5 UI主线程与耗时线程分离详细方法实例

    python GUI库图形界面开发之PyQt5 UI主线程与耗时线程分离详细方法实例

    这篇文章主要介绍了python GUI库图形界面开发之PyQt5 UI主线程与耗时线程分离详细方法实例,需要的朋友可以参考下
    2020-02-02
  • 基于Python+Pyqt5开发一个应用程序

    基于Python+Pyqt5开发一个应用程序

    今天给大家带来的是关于Python的相关知识,文章围绕着Python+Pyqt5开发一个应用程序展开,文中有非常详细的介绍及代码示例,需要的朋友可以参考下
    2021-06-06

最新评论