包含python函数隐式调用的词条( 二 )


l = [1,2,3,4]
i = iter(l)
l2 = list(i)
最后,没有列表和列表对象这种说法 。这两者一般都是指列表对象(instance of the type list) 。如果你是想说列表类(the list type)本身,可以这样得到:
type([])
或者
[].__class__
python 怎么样隐式函数调用最常用的是在类定义的方法 , 给一个property的装饰器,可以安装调用属性的方式调用
Python 数据模型 Python 风格的关键完全体现在 Python 的数据模型上 , 数据模型所描述的 API ,为使用最地道的语言特性来构建开发者自己的对象提供了工具 。
当 Python 解析器遇到特殊句法时 , 会使用特殊方法去激活一些基本的对象操作 。特殊方法以双下划线开头,以双下划线结尾 。如: obj[key]的背后就是__getitem__方法 。魔术方法是特殊方法的昵称,特殊方法也叫双下方法 。
使用__getitem__和__len__创建一摞有序的纸牌:
上面的例子 , 使用collections.namedtuple构建了一个简单的类来表示一张纸牌,namedtuple用以构建只有少数属性但没有方法的类 。
我们自定义的FrenchDeck类可以像任何 python 标准集合类型一样使用len()函数 , 查看一叠牌有多少张:
也可以像列表一样,使用位置索引,d[i]将调用__getitem__方法:
也可以使用标准库模块提供的random.choice方法,从序列中随机选取一个元素 。下面,我们如随机取出一张纸牌:
现在我们已经体会到通过 python 特殊方法 , 来使用 Python 数据模型的 2 个好处:
因为__getitem__方法把[]操作交给了self.cards列表,所以我们的FrenchDeck实例自动支持切片:
仅仅实现了__getitem__方法,这一摞牌即变得可迭代:
运行结果:
也可以直接调用内置的reversed函数,反向迭代FrenchDeck实例:
运行结果:
迭代通常是隐式的,比如一个集合类型没有实现__contains__方法,那么in运算符就会按顺序做一次迭代搜索 。
因此,in运算符可以用在我们的FrenchDeck实例上,因为它是可迭代的:
FrenchDeck还可以使用 Python 标准库中的sorted函数 , 实现排序:
首先定义一个排序依据的函数:
优先按 rank 的大小排序,rank 相同时则比较 suit 的值:
运行结果:
优先按 suit 的大小排序 , suit 相同时则比较 rank 的值:
运行结果:
按照目前的设计,FrenchDeck 还不支持洗牌,因为它是不可变的:
shuffle函数要调换集合中元素的位置,而FrenchDeck只实现了不可变的序列协议,可变的序列还必须提供__setitem__方法:
洗牌:
没有任何的返回值,可见random.shuffle就地修改了可变序列d。为便于观察结果 , 我们定义输入的输出函数:
运行结果:
每次洗牌,都是一个随机的序列:
首先明确一点 , 特殊方法的存在是为了被 Python 解析器调用的,例如:我们不会使用obj.__len__()这种写法,而是len(obj)。在执行len(obj)时,如果obj是一个自定义类的对象,那么 Python 会自己去调用我们实现的__len__方法 。
对于 Python 内置的数据类型,比如列表、字符串、字节序列等 , 那么 CPython 会抄个近路 ,  __len__实际上会返回PyVarObject里的ob_size属性,这是因为直接读取属性比调用一个方法要快得多 。
很多时候,特殊方法的调用是隐式的,比如for i in x:这个语句其实是调用iter(x) ,而这个函数的背后是x.__iter__()方法 。
通过内置函数如来使用特殊方法是最好的选择 。这些内置函数不仅会调用这些方法 , 通常还提供额外的好处,对于内置类型来说,它们的速度更快 。

推荐阅读