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提高面向对象编程效率内容请搜索编程宝库以前的文章,希望大家多多支持编程宝库

python网络爬虫之模拟登录 自动获取cookie值 验证码识别的具体实现: 1、爬取网页分析爬取的目标网址为:https://www.gushiwen.cn/在登陆界面需要做的工作有,获取验证码图片,并识别该验证码,才能实现登 ...