Skip to the content.

Fluent Python - Python数据模型

Contact me

本系列博客主页及相关见此处


Python的数据模型可以看作是一个统一的框架,同意了语言各部分的接口,包括序列,迭代器,函数,类,上下文管理器等。因此你可以使用len(collection)统一获得python容器的长度。

namedtuple

Card = collections.namedtuple('Card', ['rank', 'suit'])

提供了不错的输出表示:

>>> beer_card = Card('7', 'diamonds')
>>> beer_card
Card(rank='7', suit='diamonds')

getitem

Card = collections.namedtuple('Card', ['rank', 'suit'])
class FrenchDeck:
    ranks = [str(n) for n in range(2, 11)] + list('JQKA')
    suits = 'spades diamonds clubs hearts'.split()
    def __init__(self):
        self._cards = [Card(rank, suit) for suit in self.suits
                                        for rank in self.ranks]
    def __len__(self):
        return len(self._cards)
    def __getitem__(self, position):
        return self._cards[position]

特殊函数的使用

如果一个对象时用户自定义的类,那么len(obj)调用的是__len__,对于内置的类型,直接访问的是CPyhon内部结构体的值ob_size,这比直接调用函数更快。

对于for i in x,首先做的是调用iter(x),如果有x.__iter__()那就调用这个函数。

常用的特殊函数是__init__,用于定义初始化的内容。

通常不要直接调用特殊函数,应该直接使用相对应的内置函数len,iter等。对于内置类型,这样的调用更快。

不要随意设置__foo__

定义一个向量

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)

可以做到:

v1 + v2
abs(v)
v * 3

bool

bool通常调用__bool__,如果没有实现这个函数,python会尝试调用__len__,如果返回0,结果是False

总览

为什么len不是一个方法

如果x是一个内置类型的话,len(x)直接读取C结构体的值,非常快。