• python之使用魔术方法__getitem__和__len__


    (1)像__getitem__这种由两个双下划线构成的方法,被称为魔术方法。

    (2)魔术方法是为了给python解释器用的。当使用len(collection)时,实际上调用的就是collection.__len__方法。而在使用obj[key]的形式来访问元素时,实际上调用的是object.__getitem__(key)方法。

    (3)魔术方法是属于类的方法,也就是说不需要实例化类就可以访问到该方法,同时,实例化的对象都可以访问到该方法。

    (4)使用__getitem__和__len__方法,我们就可以实现一个对自定义数据类型的迭代和访问。

    举个例子:

    import collections
    Card = collections.namedtuple("Card",["rank","suit"])
    class FrenchDeck(object):
        ranks = [str(n) for n in range(2,11)] + list("JQKA")
        #黑桃 方块 红桃 梅花
        suits = "spades diamonds hearts clubs ".split()
        def __init__(self):
            self._cards = [Card(rank,suit) for rank in self.ranks
                           for suit in self.suits]
        def __getitem__(self, item):
            return self._cards[item]
        def __len__(self):
            return len(self._cards)

    说明:

    • Card = collections.namedtuple("Card",["rank","suit"])创建一个名字为Card的类,并且具有属性rank和suit,rank表示牌的数值,suit表示牌的花色。
    • 一个FrenchDeck类,用于生成52张扑克牌,从2-A,红桃、方块、红桃、梅花。ranks、suits以及魔术方法都是类方法。

    首先说明的是类属性和方法,直接用类名.属性或类名.方法访问即可。

    print(FrenchDeck.ranks)
    print(FrenchDeck.suits)
    print(FrenchDeck.__len__(FrenchDeck()))

    输出:

    自定义的FrenchDeck类在重写了__getitem__和__len__方法之后,就可以对FrenchDeck实例化的对象进行类似于列表的操作。

    1.得到对象的长度

    deck = FrenchDeck()
    print(len(deck))

    输出:52

    2.通过下标来获列表元素

    print(deck[0])
    print(deck[-1])

    输出:

    Card(rank='2', suit='spades')
    Card(rank='A', suit='clubs')

    3.对列表进行遍历。当然也可以使用reversed方法进行翻转遍历

    for d in reversed(deck):
        print(d)

    输出:

    Card(rank='A', suit='clubs')
    Card(rank='A', suit='hearts')
    Card(rank='A', suit='diamonds')
    Card(rank='A', suit='spades')
    Card(rank='K', suit='clubs')
    Card(rank='K', suit='hearts')
    Card(rank='K', suit='diamonds')
    Card(rank='K', suit='spades')
    Card(rank='Q', suit='clubs')
    Card(rank='Q', suit='hearts')
    Card(rank='Q', suit='diamonds')
    Card(rank='Q', suit='spades')
    Card(rank='J', suit='clubs')
    Card(rank='J', suit='hearts')
    Card(rank='J', suit='diamonds')
    Card(rank='J', suit='spades')
    Card(rank='10', suit='clubs')
    Card(rank='10', suit='hearts')
    Card(rank='10', suit='diamonds')
    Card(rank='10', suit='spades')
    Card(rank='9', suit='clubs')
    Card(rank='9', suit='hearts')
    Card(rank='9', suit='diamonds')
    Card(rank='9', suit='spades')
    Card(rank='8', suit='clubs')
    Card(rank='8', suit='hearts')
    Card(rank='8', suit='diamonds')
    Card(rank='8', suit='spades')
    Card(rank='7', suit='clubs')
    Card(rank='7', suit='hearts')
    Card(rank='7', suit='diamonds')
    Card(rank='7', suit='spades')
    Card(rank='6', suit='clubs')
    Card(rank='6', suit='hearts')
    Card(rank='6', suit='diamonds')
    Card(rank='6', suit='spades')
    Card(rank='5', suit='clubs')
    Card(rank='5', suit='hearts')
    Card(rank='5', suit='diamonds')
    Card(rank='5', suit='spades')
    Card(rank='4', suit='clubs')
    Card(rank='4', suit='hearts')
    Card(rank='4', suit='diamonds')
    Card(rank='4', suit='spades')
    Card(rank='3', suit='clubs')
    Card(rank='3', suit='hearts')
    Card(rank='3', suit='diamonds')
    Card(rank='3', suit='spades')
    Card(rank='2', suit='clubs')
    Card(rank='2', suit='hearts')
    Card(rank='2', suit='diamonds')
    Card(rank='2', suit='spades')

    4.使用choice随机抽取一张牌

    from random import choice
    print(choice(deck))

    5.利用in判断一张牌是否在对象列表中

    print(Card("Q","clubs") in deck)

    6.可以对牌组进行排序,按照花色桃心梅方以及数值大小

    def spades_high(card):
        #首先得到该卡牌在数值中的位置
        rank_value = FrenchDeck.ranks.index(card.rank)
        #返回的是其位置*4+花色对应的级别
        #比如梅花2的大小为0,黑桃A的大小为12*4+3=51
        return rank_value*len(suit_values)+suit_values[card.suit]
    #Card = Card("A","spades")
    #print(spades_high(Card))
    for card in sorted(deck,key=spades_high):
        print(card)

    输出;

    Card(rank='2', suit='diamonds')
    Card(rank='2', suit='clubs')
    Card(rank='2', suit='hearts')
    Card(rank='2', suit='spades')
    Card(rank='3', suit='diamonds')
    Card(rank='3', suit='clubs')
    Card(rank='3', suit='hearts')
    Card(rank='3', suit='spades')
    Card(rank='4', suit='diamonds')
    Card(rank='4', suit='clubs')
    Card(rank='4', suit='hearts')
    Card(rank='4', suit='spades')
    Card(rank='5', suit='diamonds')
    Card(rank='5', suit='clubs')
    Card(rank='5', suit='hearts')
    Card(rank='5', suit='spades')
    Card(rank='6', suit='diamonds')
    Card(rank='6', suit='clubs')
    Card(rank='6', suit='hearts')
    Card(rank='6', suit='spades')
    Card(rank='7', suit='diamonds')
    Card(rank='7', suit='clubs')
    Card(rank='7', suit='hearts')
    Card(rank='7', suit='spades')
    Card(rank='8', suit='diamonds')
    Card(rank='8', suit='clubs')
    Card(rank='8', suit='hearts')
    Card(rank='8', suit='spades')
    Card(rank='9', suit='diamonds')
    Card(rank='9', suit='clubs')
    Card(rank='9', suit='hearts')
    Card(rank='9', suit='spades')
    Card(rank='10', suit='diamonds')
    Card(rank='10', suit='clubs')
    Card(rank='10', suit='hearts')
    Card(rank='10', suit='spades')
    Card(rank='J', suit='diamonds')
    Card(rank='J', suit='clubs')
    Card(rank='J', suit='hearts')
    Card(rank='J', suit='spades')
    Card(rank='Q', suit='diamonds')
    Card(rank='Q', suit='clubs')
    Card(rank='Q', suit='hearts')
    Card(rank='Q', suit='spades')
    Card(rank='K', suit='diamonds')
    Card(rank='K', suit='clubs')
    Card(rank='K', suit='hearts')
    Card(rank='K', suit='spades')
    Card(rank='A', suit='diamonds')
    Card(rank='A', suit='clubs')
    Card(rank='A', suit='hearts')
    Card(rank='A', suit='spades')

    说了这么多,就是为了说明通过实现__getitem__和__len__方法,FrenchDeck就和一个python自有的序列数据类型一样了。对合成的运用使得__len__和__getitem__的具体实现可以代理给self._card这个python列表

  • 相关阅读:
    AGC041
    二分图 学习笔记
    区间DP 学习笔记
    3月21日考试 题解(数据结构+区间DP+贪心)
    Tarjan 做题总结
    3月15日考试 题解(数学+背包+线段树)
    差分约束 学习笔记
    Tarjan算法 学习笔记
    拓扑排序 学习笔记
    并查集 学习笔记
  • 原文地址:https://www.cnblogs.com/xiximayou/p/12164274.html
Copyright © 2020-2023  润新知