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

目录
  • 1、attrs的使用
  • 2、验证器
  • 3、转换器

前言:

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提高面向对象编程效率内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • Python数据分析JupyterNotebook3魔法命令详解及示例

    目录 1.魔法命令介绍 %lsmagic:列出所有magics命令 %quickref:输出所有魔法指令的简单版帮助文档 %Magics_Name?:输出某个魔法命令详细帮助文档 2.Line magics:Line魔法指令 3.Cell magics:Cell魔法指令 写bash程序 写perl程序 1.魔法命令介绍 %lsmagic:列出所有magics命令 Available line magics:[对当前行使用共计93个] %alias %alias_magic %autoawait

  • 用Python做个自动化弹钢琴脚本实现天空之城弹奏

    目录 一.核心功能设计 二.实现步骤 1. 演奏函数 2. 添加演奏旋律多线程 3. 手指演奏曲谱 4. 钢琴模拟演奏 前言 小时候一直有一个想成为钢琴家的梦想,最近在网上看到了一个开源的钢琴演奏网页autopiano,可以支持键盘按键弹奏.鼠标点击弹奏. 首先一起来看看最终实现的演奏效果: 下面,我们就开始介绍如何实现这个自动化弹钢琴脚本的. 一.核心功能设计 总体的实现相对是比较简单的,主要分为以下4步实现: 实现演奏函数,通过手指及时间间隔模拟弹钢琴 添加各个演奏旋律线程,通过多线程模拟双

  • Python pymysql操作MySQL详细

    目录 1.使用 1.1 简单使用 1.2 封装工具类 1.使用 1.1 简单使用 import pymysql # 创建连接 con = pymysql.connect( host='localhost', port=3306, user='root', password='123456', database='test', charset='utf8' ) # 创建游标 cursor = con.cursor() # 执行新增SQL,返回受影响行数 row1 = cursor.execute(

  • Python可视化Matplotlib介绍和简单图形的绘制

    目录 1. 什么是Matplotlib 2. 实现一个最简单的Matplotlib画图以折线图为例 2.1 matplotlib.pyplot模块 2.2 图形绘制流程 1.创建画布 – plt.figure() 2.绘制图像 – plt.plot(x, y) 3.显示图像 – plt.show() 2.3 折线图绘制与显示 1. 什么是Matplotlib matplotlib是专门用于开发2D图表(包括3D图表),以渐进.交互式方式实现数据可视化.使用python对matplotlib库操作

  • Python 使用 attrs 和 cattrs 实现面向对象编程的实践

    Python 是支持面向对象的,很多情况下使用面向对象编程会使得代码更加容易扩展,并且可维护性更高,但是如果你写的多了或者某一对象非常复杂了,其中的一些写法会相当相当繁琐,而且我们会经常碰到对象和 JSON 序列化及反序列化的问题,原生的 Python 转起来还是很费劲的. 可能这么说大家会觉得有点抽象,那么这里举几个例子来感受一下. 首先让我们定义一个对象吧,比如颜色.我们常用 RGB 三个原色来表示颜色,R.G.B 分别代表红.绿.蓝三个颜色的数值,范围是 0-255,也就是每个原色有 25

  • Python可视化Matplotlib折线图plot用法详解

    目录 1.完善原始折线图 - 给图形添加辅助功能 1.1 准备数据并画出初始折线图 1.2 添加自定义x,y刻度 1.3 中文显示问题解决 1.4 添加网格显示 1.5 添加描述信息 1.6 图像保存 2. 在一个坐标系中绘制多个图像 2.1 多次plot 2.2 显示图例 2.3 折线图的应用场景 折线图是数据分析中非常常用的图形.其中,折线图主要是以折线的上升或下降来表示统计数量的增减变化的统计图.用于分析自变量和因变量之间的趋势关系,最适合用于显示随着时间而变化的连续数据,同时还可以看出数

  • Python中字典的基础介绍及常用操作总结

    目录 1.字典的介绍 2.访问字典的值 (一)根据键访问值 (二)通过get()方法访问值 3.修改字典的值 4.添加字典的元素(键值对) 5.删除字典的元素 6.字典常见操作 1.len 测量字典中键值对的个数 2. keys 返回一个包含字典所有KEY的列表 3. values 返回一个包含字典所有value的列表 4. items 返回一个包含所有(键,值)元祖的列表 5.遍历字典的key(键) 6.遍历字典的value(值) 7.遍历字典的items(元素) 8.遍历字典的items(键

  • Python之集合详解

    目录 集合的基本操作 1.添加元素 add() update() 2.移除元素 remove() clear() 3.集合的交集 什么是交集? intersection() 3.集合的并集 什么是并集? union() 总结 集合(set)是一个无序的不重复元素序列. 可以使用大括号 { } 或者 set() 函数创建集合. student = {'小明', 'xiaohong', 'adm'} print('student的数据类型', type(student)) # student的数据类

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

    目录 1.attrs的使用 2.验证器 3.转换器 前言: Python是面向对象的语言,一般情况下使用面向对象编程会使得开发效率更高,软件质量更好,并且代码更易于扩展,可读性和可维护性也更高.但是如果在一个较大的项目中,如果实体类非常多并且有非常复杂的属性,你就会逐渐觉得Python的类写起来是真·"累".为什么这样说,看下下面这个Box类,属性有长(length).宽(width).高(hight): class Box: def __init__(self, length, wi

  • Python中关于面向对象概念的详细讲解

    面向对象编程的2个非常重要的概念: 类和对象 对象是面向对象编程的核心,在使用对象的过程中,为了将具有共同特征和行为的一组对象抽象定义,提出了另外一个新的概念--类. 类用来描述具有相同的属性和方法的对象的集合.它定义了该集合中每个对象所共有的属性和方法.对象是类的实例. 类是由三部分构成: 类的名称 类的属性 类的方法 格式如下: # 类名 class Func(object): # 类的属性 i=123 # 类的方法 def f(self): print('6666') # 实例化类 a=F

  • Python学习之面向对象编程详解

    目录 什么是面向对象编程(类) 类的关键字-class 类的定义与使用 类的参数-self self的解析与总结 类的构造函数 构造函数的创建方法 关于对象的生命周期 什么是面向对象编程(类) 利用(面向)对象的(属性和方法)去进行编码的过程即面向对象编程 自定义对象数据类型就是面向对象中的类(class)的概念 类的关键字 - class class 关键字用来声明类,类的名称首字母大写,多单词的情况下每个单词首字母大写(即驼峰命名法).在我们一开始学习 Python 的时候说过,要尽量避免使

  • 简述Python中的面向对象编程的概念

    面向对象编程--Object Oriented Programming,简称OOP,是一种程序设计思想.OOP把对象作为程序的基本单元,一个对象包含了数据和操作数据的函数. 面向过程的程序设计把计算机程序视为一系列的命令集合,即一组函数的顺序执行.为了简化程序设计,面向过程把函数继续切分为子函数,即把大块函数通过切割成小块函数来降低系统的复杂度. 而面向对象的程序设计把计算机程序视为一组对象的集合,而每个对象都可以接收其他对象发过来的消息,并处理这些消息,计算机程序的执行就是一系列消息在各个对象

  • 从0开始的Python学习014面向对象编程(推荐)

    简介 到目前为止,我们的编程都是根据数据的函数和语句块来设计的,面向过程的编程.还有一种我们将数据和功能结合起来使用对象的形式,使用它里面的数据和方法这种方法叫做面向对象的编程. 类和对象是面向对象编程的两个重要方面.对于类和对象的关系,举个例子就像学生和小明同学的关系一样.学生(类)是一个拥有共同属性的群体,小明同学(对象)是其中一个有自己特性的个体. 对于一个对象或类的变量被称为域,函数被称为类或对象的方法. 域有两种类型--属于每个对象或属于类本身,分别成为实例变量和类变量. 类使用cla

  • 提高PHP编程效率的方法

    1.如果能将类的方法定义成static,就尽量定义成static,它的速度会提升将近4倍.2.$row['id'] 的速度是$row[id]的7倍.3.echo 比 print 快,并且使用echo的多重参数(译注:指用逗号而不是句点)代替字符串连接,比如echo $str1,$str2.4.在执行for循环之前确定最大循环数,不要每循环一次都计算最大值,最好运用foreach代替.5.注销那些不用的变量尤其是大数组,以便释放内存.6.尽量避免使用__get,__set,__autoload.7

  • 提高PHP编程效率 引入缓存机制提升性能

    因为PHP会在双引号包围的字符串中搜寻变量,单引号则不会,注意:只有echo能这么做,它是一种可以把多个字符串当作参数的"函数"(译注:PHP手册中说echo是语言结构,不是真正的函数,故把函数加上了双引号). 1.如果能将类的方法定义成static,就尽量定义成static,它的速度会提升将近4倍. 2.$row['id'] 的速度是$row[id]的7倍. 3.echo 比 print 快,并且使用echo的多重参数(译注:指用逗号而不是句点)代替字符串连接,比如echo $str

  • 提高php编程效率技巧

    用单引号代替双引号来包含字符串,这样做会更快一些.因为PHP会在双引号包围的字符串中搜寻变量,单引号则 不会,注意:只有echo能这么做,它是一种可以把多个字符串当作参数的"函数"(译注:PHP手册中说echo是语言结构,不是真正的函数,故把函数加 上了双引号).    1.如果能将类的方法定义成static,就尽量定义成static,它的速度会提升将近4倍. 2.$row['id'] 的速度是$row[id]的7倍. 3.echo 比 print 快,并且使用echo的多重参数(译注

  • 提高PHP编程效率的53个要点(经验小结)

    用单引号代替双引号来包含字符串,这样做会更快一些.因为PHP会在双引号包围的字符串中搜寻变量,单引号则不会,注意:只有echo能这么做,它是一种可以把多个字符串当作参数的"函数"(译注:PHP手册中说echo是语言结构,不是真正的函数,故把函数加上了双引号). 1.如果能将类的方法定义成static,就尽量定义成static,它的速度会提升将近4倍. 2.$row['id'] 的速度是$row[id]的7倍. 3.echo 比 print 快,并且使用echo的多重参数(译注:指用逗号

  • Python中的面向对象编程详解(下)

    继承 继承描述了基类的属性如何"遗传"给派生类.一个子类可以继承它的基类的任何属性,不管是数据属性还是方法. 创建子类的语法看起来与普通(新式)类没有区别,一个类名,后跟一个或多个需要从其中派生的父类: 复制代码 代码如下: class SubClassName (ParentClass1[, ParentClass2, ...]):     'optional class documentation string'     class_suite 实例 复制代码 代码如下: clas

随机推荐