learn with python-第十五章:对象的集合

来源:互联网 发布:海量数据去重 编辑:程序博客网 时间:2024/05/29 04:37
十五章:对象的集合
15.1复合对象
目前我们看到几种符合对象的方式,前面章节中将方法的调用做作为表达式的一部分,另外一种使用嵌套递归的结构的方式是在while循环中使用if语句
这种模式中你会看到我们创建对象集合,你也可以创建一个集合作为对象的属性,列表也可以作为列表的元素。本章中我们会使用Card对象作为示例。

15.2Card对象
如果你对纸牌不熟,那么正好可以借这个机会熟悉纸牌。一副纸牌包含52张牌,属于四种花色,每种花色包含13张牌,ace,2,3,4,5,6,7,8,9,10,j,q和k,不同的玩法中ace可能最大也可能最小。
如果我们想定义一个新的对象表示玩纸牌,显然新的对象应该有排序以及组合的属性,但是具体的属性类型并不明显,一种方式是使用字符串,但是这种方式的缺点就是不容易对纸牌的大小以及排序进行比较。

另外一种方式就是使用数字去编码排序以及组合,这里的编码不是通常所说的加密字符使其密文,而是建立数字序列和纸牌之间的映射关系。
Spades ——> 3
Hearts ——>  2
Diamonds ——>  1
Clubs ——>  0

class Card:
    def __init__(self, suit=0, rank=0):
        self.suit = suit
        self.rank = rank

我们为每个参数设置了一个默认值,创建一个表示 梅花3的纸牌我们可以使用表达式:
threeOfClubs = Card(0,3)
第一个参数0表示纸牌的花色,第二个参数表示纸牌的值

15.3类属性以及__str__方法
为了便于阅读,我们将数字映射到字符串,通常的做法是使用字符串列表,我们在class的顶部定义属性并 赋值。
class Card:
    suitList = ['Clubs','Diamonds','Hearts','Spades']
    rankList = ["narf", "Ace", "2", "3", "4", "5", "6", "7","8", "9", "10", "Jack", "Queen", "King"]
    def __str__(self):
        return (self.rankList[self.rank] + " of " + self.suitList[self.suit])
类的属性是在方法之外定义的,在类的所有方法中都可以进行访问。
__str__方法中,我们使用suitList和rankListh排序和集合和数字之间进行映射,表达式self.suitList[self.suit]表示从列表中获取下标为self.suit的字符串。
字符串narf作为列表第一个元素表示下标为0的元素,这个元素不会被使用,合法的排序是1到13。
目前为止我们创建一个纸牌并答应:
>>> card1 = Card(1, 11)
>>> print card1
Jack of Diamonds
如Card对象中的suitList属性,类的属性被所有的类对象所共有,我们可以在任意对象中对类属性进行访问。
>>> card2 = Card(1, 3)
>>> print card2
3 of Diamonds
>>> print card2.suitList[1]
Diamonds
其缺点就是如果更改了类的属性,那么类的所有实例都会受到影响,通常不推荐更改类的属性值。

15.4纸牌的比较
对于内置的类型,有操作符<>==等进行比较大小,对于自定义的类型,我们可以通过重写__cmp__方法重写这些内置操作符,该方法接受两个参数,self以及other,如果第一个参数大则返回1,如果第二个参数较大则返回-1.如果相等返回0。
某些类型已经定义了排序,那么你可以对其中的任意两个进行大小比较,例如:可以比较整数和浮点数的大小,某些集合没有定义排序,那么将两则进行比较则无意义。
纸牌的集合部分排序,意味着有些时候你可以进行排序,有些时候则无法进行排序。例如:梅花3比梅花2大,那么方块3和梅花2的大小呢?一个花色较大,一个数值较大,为了让任意纸牌可以进行比较,你必须定义其规则。
决定了规则那么重写__cmp__方法。
 def __cmp__(self, other):
        if self.suit > other.suit:
            return 1
        if self.suit < other.suit:
            return -1
        if self.rank > other.rank:
            return 1
        if self.rank < other.rank:
            return -1
        return 0

15.5Deck
现在我们有对象表示扑克牌,下一步我们需要类可以表示Deck,当然Deck由牌的集合构成,因此拥有一个包含纸牌的集合属性。
下面是Deck类的定义,初始化方法创建包含五十二章纸牌的集合:
class Deck:
    def __init__(self):
        self.cards = []
        for suit in range(4):
            for rank in range(1,14):
                self.cards.append(Card(suit, rank))
初始化Deck的最简单方式就是嵌套循环,内层循环suit从0到3,外层循环rank从1到13,嵌套循环执行完之后就有52张初始牌。

15.6打印Deck
同往常,我们定义了一个类的同时我们已定义一个打印其内容的方法,对于Deck我们想打印其中每张牌:
 def __str__(self):
        for card in self.cards:
            print(card)
另外一种方式我们可以重写__str__方法,重写__str__的优势是我们可以获得一个表示deck内容的字符串而不仅仅是将其打印出来,
def __str__(self):
    s = ""
    for i in range(len(self.cards)):
        s = s + " "*i + str(self.cards[i]) + "\n"
    return s

15.7洗牌
一副牌的顺序不可能是完全排序好的,而应该是随机的。我们可以使用random模块中的randrange来实现洗牌,对于两个整数参数a和b,randrange挑选一个大于等于a小于b的整数,我们使用数列的长度作为第二个值
random.randrange(0, len(self.cards)),一种简单的洗牌算法就是每张牌都和随机选中的牌进行交换。
 def shuffle(self):
        import random
        nCards = len(self.cards)
        for i in range(nCards):
            j = random.randrange(i, nCards)
            self.cards[i],self.cards[j] = self.cards[j], self.cards[i]


15.8出牌
另外一个方法是移除牌,该方法接受一个card对象作为参数,从扑克牌中移除这张牌,如果这张牌在扑克牌中返回1,如果没有找到则返回0
def removeCard(self, card):
        if card in self.cards:
            self.cards.remove(card)
            return 1
        else:
            return 0
操作符in接受两个参数,如果第一个参数在第二个参数中返回true,否则返回false.python使用__cmp__方法判断对象是否相等。
我们想移除并返回第一张牌,pop方法提供了实现
def popCard(self):
    return self.cards.pop()
方法isEmpty用于判断是否还有牌
def isEmpty(self):
        return (len(self.cards) == 0)

最后完整的版本:
class Card:
    suitList = ['Clubs','Diamonds','Hearts','Spades']
    rankList = ["narf", "Ace", "2", "3", "4", "5", "6", "7","8", "9", "10", "Jack", "Queen", "King"]
    def __init__(self, suit=0, rank=0):
        self.suit = suit
        self.rank = rank
    def __str__(self):
        return (self.rankList[self.rank] + " of " + self.suitList[self.suit])
    def __cmp__(self, other):
        if self.suit > other.suit:
            return 1
        if self.suit < other.suit:
            return -1
        if self.rank > other.rank:
            return 1
        if self.rank < other.rank:
            return -1
        return 0
class Deck:
    def __init__(self):
        self.cards = []
        for suit in range(4):
            for rank in range(1,14):
                self.cards.append(Card(suit, rank))
    def printDeck(self):
        for card in self.cards:
            print(card)
    def shuffle(self):
        import random
        nCards = len(self.cards)
        for i in range(nCards):
            j = random.randrange(i, nCards)
            self.cards[i],self.cards[j] = self.cards[j], self.cards[i]
    def removeCard(self, card):
        if card in self.cards:
            self.cards.remove(card)
            return 1
        else:
            return 0
    def popCard(self):
        return self.cards.pop()
    def isEmpty(self):
        return (len(self.cards) == 0)
deck = Deck()
deck.shuffle()
deck.printDeck()

0 0
原创粉丝点击