fluent python (一)python数据模型

fluent python (一)python数据模型

__getitem__和__len__ 的实现方法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import collections

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]

beer_card = Card('7', 'diamonds')
print(beer_card)

这里先利用connections里的namedtuple函数返回了一个新的type。新建一个扑克牌的类。

做一点测试:

1
2
3
4
5
6
7
8
9
10
deck = FrenchDeck()
print(len(deck))
print(deck[0])
print(deck[1])
print(deck[-1])

from random import choice
print(choice(deck))
print(choice(deck))
print(choice(deck))

我们使用len的时候就会自动调用__len__这个特殊方法。我们同时也实现了__getitem__这个方法,也可以利用索引来查看元素了。

迭代通常是隐式的,比如说一个集合类型没有实现__contains__方法,那么in运算符就会按顺序做一次迭代搜索。

1
2
3
4
5
6
7
suit_values = dict(spades=3, hearts=2, diamonds=1, clubs=0)
def spades_high(card):
rank_value = FrenchDeck.ranks.index(card.rank)
return rank_value * len(suit_values) + suit_values[card.suit]

for card in sorted(deck, key=spades_high):
print(card)

手写排序规则。

使用特殊方法

特殊方法是被Python解释器调用的,我们不需要直接使用_len\_特殊方法,而应该使用len(),他会自动调用该对象的__len__特殊方法。

如果是Python内置的类型(如list,str,bytearray),那么CPython会直接返回PyVarObject里的ob_size这个属性,PyVarObject是表示内存中长度可变的内置对象的C语言结构体,会快很多。

特殊方法的调用是隐式的,比如for i in x:背后调用的是x.__iter__()方法(前提是已经实现了)。

通常无需直接使用特殊方法,除非有大量的愿变成存在。例外:__init__方法可能会经常用到,目的是在自己的子类的__init__方法中调用超类的构造器。

通过内置的函数(如len,str,iter)来使用特殊方法往往会有额外的好处,谨记不要想当然的随意添加特殊方法。

简单二维向量的实现

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(self.x or self.y)

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)

这里实现了6个特殊方法,具体自己尝试。

Python内有一个repr函数,调用了__repr__特殊方法来获得对象的字符串表示形式。如果没有实现的话,返回的就有可能是一个地址了。这里利用%r来获取对象各个属性的标准字符串表示形式。

__repr__和__str__的区别主要在于后者是在str()函数被使用或者print()函数才会被调用,如果一个对象没有__str__方法会用__repr__来替代。

其他的一些特殊方法:Click me

文章目录
  1. 1. fluent python (一)python数据模型
    1. 1.1. __getitem__和__len__ 的实现方法。
    2. 1.2. 使用特殊方法
      1. 1.2.1. 简单二维向量的实现
|