目录

Python 数据模型

1. 语言特性

  1. Python 最好的品质之一是一致性,体现在 Python 的数据模型上

2. 数据模型

定义:是对 Python 框架的描述
作用:规范了这门语言自身构建模块的接口(API)
包括:不限于序列、迭代器、函数、类和上下文管理器

  • 数据模型接口:

    • 实现: Python 解释器碰到特殊的句法时,会使用特殊方法去激活一些基本的对象操作
    • 特殊方法:以两个下划线开头,以两个下划线结尾
  • 通过特殊方法可以实现的语言框架:

    • 迭代
    • 集合类
    • 属性访问
    • 运算符重载
    • 函数和方法的调用
    • 对象的创建和销毁
    • 字符串表示形式和格式化
    • 管理上下文(即 with 块)
  • 通过实现特殊方法来利用 Python 数据模型的好处:

    • 作为你的类的用户,他们不必去记住标准操作的各式名称
    • 可以更加方便地利用 Python的标准库 eg:random.choice

3. 使用特殊方法

特殊方法调用:

  • 特殊方法的存在是为了被 Python 解释器调用的,不需要直接调用它们
  • 最好的选择是通过内置的函数(例如 len、 iter、 str,等等)
    eg:len(obj) 会自动调用 obj.__len__()方法
  • Python 内置的类型, CPython可能直接从一个 C 结构体里读取数据

__repr__

作用:

  • 方便程序员调试和记录日志
  • 所返回的字符串应该准确、无歧义,并且尽可能表达出如何用代码创建出这个被打印的对象

调用:

  • repr() 函数
  • “%r” % obj
  • format(’{name!r}’, obj)
  • 交互式控制台和调试程序(debugger)用 repr 函数获取字符串表示形式
  • 如果对象没有 __str__ 函数,解释器会用 __repr__ 作为替代

__str__

作用:

  • 终端用户使用

调用:

  • str()
  • print

__bool__

调用: bool()
python 真假判断:

  • 为了判定值 x 真假, Python会调用 bool(x),这个函数只能返回 True 或者 False
  • bool(x)默认调用 x.__bool__(),__bool__ 必须返回布尔型
  • 如果不存在,bool(x) 尝试调用 x.__len__()返回 0则 bool 返回 False;否则返回 True
  • 两个方法都不存在,默认情况下,自定义的类的实例总是返回True

特殊方法概览

1. 跟运算符无关的特殊方法

类别 方法名
字符串/字节序列表示形式 __repr__、 __str__、 __format__、 __bytes__
数值转换 __abs__、 __bool__、 __complex__、 __int__、 __float__、 __hash__、 __index__
集合模拟 __len__、 __getitem__、 __setitem__、 __delitem__、 __contains__
迭代枚举 __iter__、 __reversed__、 __next__
可调用模拟 __call__
上下文管理 __enter__、 __exit__
实例创建和销毁 __new__、 __init__、 __del__
属性管理 __getattr__、 __getattribute__、 __setattr__、 __delattr__、 __dir__
属性描述符 __get__、 __set__、 __delete__
跟类相关的服务 __prepare__、 __instancecheck__、 __subclasscheck__

2. 跟运算符相关的特殊方法

类别 方法名和对应的运算符
一元运算符 __neg__ -、 __pos__ +、 __abs__ abs()
众多比较运算符 __lt__ <、 __le__ <=、 __eq__ ==、 __ne__ !=、 __gt__ >、 __ge__ >=
算术运算符 __add__ +、 __sub__ -、 __mul__ *、 __truediv__ /、 __floordiv__ //、 __mod__ %、 __divmod__ divmod()、 __pow__ ** 或 pow()、 __round__ round()
反向算术运算符 __radd__、 __rsub__、 __rmul__、 __rtruediv__、 __rfloordiv__、 __rmod__、__rdivmod__、 __rpow__
增量赋值算术运算符 __iadd__、 __isub__、 __imul__、 __itruediv__、 __ifloordiv__、 __imod__、__ipow__
位运算符 __invert__ ~、 __lshift__ «、 __rshift__ »、 __and__ &、 __or__ 、 __xor__ ^
反向位运算符 __rlshift__、 __rrshift__、 __rand__、 __rxor__、 __ror__
增量赋值位运算符 __ilshift__、 __irshift__、 __iand__、 __ixor__、 __ior__

附注

len 为什么不是普通方法

  • 对于内置类型,len() 直接从C 结构体里读取对象长度,完全不会调用任何方法
  • len 之所以不是一个普通方法,是为了让 Python 自带的数据结构 可以走后门,其他内置函数也是同样道理
  • 同时由于它是特殊方法,也可以把 len 用于自定义数据类型
  • 这种处理方式在保持内置类型的效率和保证语言的一致性之间找到了一个平衡点

4. 常用模块

模块 作用
collection.namedtuple() 构建只有少数属性但是没有方法的对象,比如数据库条目
random.choice(seq) 从一个序列中随机选出一个元素
sorted() 内置排序函数
decimal.Decimal 高精度浮点数
fractions.Fraction 分数数值类型

延伸阅读

Python:

书籍:

  • 《 Python 技术手册(第 2 版)》- 对属性访问机制的描述
  • 《 Python 参考手册(第 4 版)》
  • 《 Python Cookbook(第 3版)中文版》
  • 《The Art of the Metaobject Protocol》 - 元对象协议(metaobject protocol, MOP)

blog:

杂谈

元对象协议

  • 元对象所指的是那些对建构语言本身来讲很重要的对象,
  • 以此为前提, 协议也可以看作接口
  • 也就是说,元对象协议是对象模型的同义词,它们的意思都是构建核心语言的 API

面向方面编程

示例代码

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
from math import hypot

class Vector:

    def __init__(self, x=0, y=0):
        self.x = x
        self.y = y

    def __repr__(self):
        return 'Vector(%r, %r)' % (self.x, self.y)

    def __abs__(self):
        return hypot(self.x, self.y)

    def __bool__(self):
        return bool(abs(self))

    def __add__(self, other):
        x = self.x + other.x
        y = self.y + other.y
        return Vector(x, y)

    def __mul__(self, scalar):
        return Vector(self.x * scalar, self.y * scalar)