学习《流畅的Python》 第1章 Python数据模型

1.1 Python 风格

直接看代码吧,比较重要的东西都做了注释。 

import collections
from random import choice

'''namedtuple加入到Python里,用以构建只有少数属性但没有方法的对象'''
Card = collections.namedtuple('Card', ['rank', 'suit'])

class FrenchDeck:
    ranks = [str(n) for n in list(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]

deck = FrenchDeck()

'''对于一个类,它和集合一样可以使用len()来查看长度'''
print(len(deck)) # 52

'''获取指定元素都由__getitem__方法提供'''
print(deck[0]) # Card(rank='2', suit='spades')
print(deck[-1]) # Card(rank='A', suit='hearts')

'''Python内置了从一个序列中随机选出一个元素的函数random.choice'''
print(choice(deck)) # Card(rank='2', suit='hearts')
print(choice(deck)) # Card(rank='4', suit='clubs')
print(choice(deck)) # Card(rank='K', suit='diamonds')

'''因为__getitem__方法把[]操作交给了self._cards列表,所以deck类自动支持切片(slicing)操作'''
print(deck[:3]) # [Card(rank='2', suit='spades'), Card(rank='3', suit='spades'), Card(rank='4', suit='spades')]
print(deck[12::13]) # [Card(rank='A', suit='spades'), Card(rank='A', suit='diamonds'), Card(rank='A', suit='clubs'), Card(rank='A', suit='hearts')]

'''因为实现了__getitem__方法,deck就变成可迭代的了'''
for card in deck:
    print(card) # ...
                # Card(rank='6', suit='spades')
                # Card(rank='7', suit='spades')
                # Card(rank='8', suit='spades')
                # Card(rank='9', suit='spades')
                # ...
# 反向迭代
for card in reversed(deck):
    print(card)

'''给纸牌排序'''
suit_values = dict(spades=3, hearts=2, diamonds=1, clubs=0)

def spades_high(card):
    rank_value = FrenchDeck.ranks.index(card.rank) # FrenchDeck中rank的索引,比如2的索引是0
    return rank_value * len(suit_values) + suit_values[card.suit]

for card in sorted(deck, key=spades_high):
    print(card) # Card(rank='2', suit='clubs')
                # Card(rank='2', suit='diamonds')
                # Card(rank='2', suit='hearts')
                # Card(rank='2', suit='spades')
                # Card(rank='3', suit='clubs')
                # Card(rank='3', suit='diamonds')
                # Card(rank='3', suit='hearts')
                # Card(rank='3', suit='spades')
                # ...

总结:

1. __len__和__getitem__是很重要的方法,也是很好用的。例如,在深度学习中,如果要构建自己的数据集就会使用到这两种方法。作者利用这个程序来告诉大家,Python和别的语言的不同之处。如书中所言:“没有my_object.__len__()这种写法,而应该使用len(my_object),如果my_object是一个自定义类的对象,那么Python会自己调用由你实现的__len__方法。”

1.2.1 模拟数值类型

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 = Vector(2, 4) 
v2 = Vector(2, 1)
print(v1 + v2) # Vector(4, 5)

v = Vector(3, 4)
print(abs(v)) # 5.0

print(v * 3) # Vector(9, 12)
print(abs(v * 3)) # 15.0

设置断点就能清楚地看见每个函数的调用过程。

你可能感兴趣的:(Python)