Python作为一种多范式语言,它的很多语言特性都能从其他语言上找到参照,但是Python依然形成了一套自己的“Python 风格”(Pythonic)。这种Pythonic风格完全体现在 Python 的数据模型上,而数据模型中的元接口(指那些名字以两个下划线开头,以两个下划线结尾的特殊方法,例如 __getitem__),就是编写地道的Python代码的秘密所在。这种基于元接口实现的设计模式,也叫鸭子类型(duck typing)。
鸭子类型指的是对象的类型无关紧要,只要实现了特定的接口即可。忽略对象的真正类型,转而关注对象有没有实现所需的方法、签名和语义。Python的数据模型都支持鸭子类型,鸭子类型也是地道Python编程鼓励的风格,所以如果觉得自己想创建新的抽象基类,先试着通过常规的鸭子类型来解决问题。
数据模型其实是对 Python 框架的描述,它规范了这门语言自身构建模块的接口,这些模块包括类、函数、序列、迭代器、上下文管理器等。
类得益于 Python 数据模型,自定义类的行为可以像内置类型那样自然。实现如此自然的行为,靠的不是继承,而是元接口。Python给类设计了大量的元接口,具体请参看Python 语言参考手册中的“Data Model”章节。下面是一些类的元接口的展示。
""" >>> v1 = Vector2d(3, 4) 通过元接口__iter__支持拆包 >>> x, y = v1 >>> x, y (3.0, 4.0) 通过元接口__repr__支持字面量表示和repr函数 >>> v1 Vector2d(3.0, 4.0) >>> v1_clone = eval(repr(v1)) >>> v1 == v1_clone True 通过元接口__str__支持print函数 >>> print(v1) (3.0, 4.0) 通过元接口__bytes__支持bytes函数 >>> octets = bytes(v1) >>> octets b\'d\\x00\\x00\\x00\\x00\\x00\\x00\\x08@\\x00\\x00\\x00\\x00\\x00\\x00\\x10@\' 通过元接口__abs__支持abs函数 >>> abs(v1) 5.0 通过元接口__bool__支持bool函数 >>> bool(v1), bool(Vector2d(0, 0)) (True, False) 通过property支持可读属性 >>> v1.x, v1.y (3.0, 4.0) >>> v1.x = 123 Traceback (most recent call last): ... AttributeError: can\'t set attribute 通过__hash__支持对象可散列,支持dict、set等函数 >>> hash(v1) 7 >>> set(v1) {3.0, 4.0} >>> {v1: \'point1\'} {Vector2d(3.0, 4.0): \'point1\'} """ from array import array import math class Vector2d: typecode = \'d\' def __init__(self, x, y): self.__x = float(x) self.__y = float(y) @property def x(self): return self.__x @property def y(self): return self.__y def __iter__(self): return (i for i in (self.x, self.y)) def __repr__(self): class_name = type(self).__name__ return \'{}({!r}, {!r})\'.format(class_name, *self) def __str__(self): return str(tuple(self)) def __bytes__(self): return (bytes([ord(self.typecode)]) + bytes(array(self.typecode, self))) def __eq__(self, other): return tuple(self) == tuple(other) def __hash__(self): return hash(self.x) ^ hash(self.y) def __abs__(self): return math.hypot(self.x, self.y) def __bool__(self): return bool(abs(self))