【流畅的Python0101】Python数据模型

1. 特殊方法示例:一摞Python风格的纸牌

import collections

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

class FrenchDeck: # Python2中要写成FrenchDeck(object)
    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] # Python 会忽略代码里 []、 {} 和 () 中的换行

    def __len__(self):
        return len(self._cards)

    def __getitem__(self, position):
        return self._cards[position]

仅仅实现了__getitem__方法,这一摞牌就变成可迭代的了,并且支持切片操作

实现spades_high函数,就可以对这摞牌进行升序排序了:

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)

2. 更多特殊方法

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)

实现__abs__, __bool__, __add__, __mul__方法就能对Vector对象进行对应的操作

  • __repr__方法
  1. __repr__ 的实现中,我们用到了 %r 来获取对象各个属性的标准字符串表示形式——这是个好习惯,它暗示了一个关键: Vector(1, 2)Vector('1', '2') 是不一样的,后者在我们的定义中会报错,因为向量对象的构造函数只接受数值,不接受字符串

  2. __repr____str__ 的区别在于,后者是在 str() 函数被使用,或是在用 print 函数打印一个对象的时候才被调用的。如果一个对象没有__str__函数,解释器会用__repr__代替

  • __bool__方法
  1. 默认情况下,我们自己定义的类的实例总被认为是真的。如果类不存在 __bool__ 方法,那么 bool(x)会尝试调用 x.__len__()。若返回 0,则 bool 会返回 False;否则返回 True。
posted @ 2023-03-08 15:48  backtosouth  阅读(17)  评论(0编辑  收藏  举报