• 《流畅的Python》一副扑克牌中的难点


    1.现在在看《流畅的Python》这本书,看了三页就发现,这本书果然不是让新手来入门的,一些很常见的知识点能被这个作者玩出花来,

    唉,我就在想,下面要分析的这些的代码,就算我费劲巴拉的看懂了,又有什么用呢,我其实不想靠着技术吃饭,但是现在在这个岗位上,

    就得在其位谋其职,悲哀。我在敲代码方面也没什么天赋,也没什么热情,老话说得好,‘女怕嫁错郎,男怕入错行’,

    所以我得从IT行业抽出身来。anyway,进入正题。

    2.python解释器碰到特殊的句法时,会使用特殊方法去激活一些基本的对象操作,这些特殊方法的名字以两个下划线开头,

    以两个下划线结尾(例如__getitem__)。比如obj[key]的背后就是__getitem__方法,为了求得my_collection[key]的值,解释器实际上会调用my_collection.__getitem__(key),双下划线这种特殊方法也叫双下方法(dunder method).

    import collections
    
    Card = collections.namedtuple('Card',['rank','suit'])
    
    
    class FrenchDeck:
        ranks = [str(n) for n in range(2,11)] + list('JQKA')
        # ['2', '3', '4', '5', '6', '7', '8', '9', '10', 'J', 'Q', 'K', 'A']
        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):
            # print("用的是我写的lenth")
            # 如果不写这个方法,用len(deck)时会报错:TypeError: object of type 'FrenchDeck' has no len()
            return len(self._cards)
    
        def __getitem__(self, position):
            return self._cards[position]
    
    >>> beer_card = Card('7','hearts')
    >>> beer_card
    Card(rank='7', suit='hearts')
    这张牌就是红心7
    
    FrenchDeck类中的self._cards生成了一个有52张'牌'的列表
    [Card(rank='2', suit='spades'), Card(rank='3', suit='spades'), ...共52个]
    suits = ['spades', 'diamonds', 'clubs', 'hearts']
    namedtuple的作用:
    >>> beer_card = Card('7','hearts')
    >>> beer_card
    Card(rank='7', suit='hearts')
    FrenchDeck类支持的方法:
    >>> deck = FrenchDeck()
    >>> len(deck)
    52
    >>> from random import choice
    >>> choice(deck)
    支持分片:只看牌面是A的牌--先抽出索引是12的那张牌,然后每隔13张拿一张
    >>> deck[12::13]
    [Card(rank='A', suit='spades'), Card(rank='A', suit='diamonds'),
     Card(rank='A', suit='clubs'), Card(rank='A', suit='hearts')]
    这个我觉得作者的用法很好
    仅仅用__getitem__方法,使这一摞牌变成可迭代
    >>> for card in deck:
    ...     print(card)
    反向迭代
    >>> for card in reversed(deck):
    ...     print(card)
    一个集合类型如果没有实现__contains__方法,in运算符就会按顺序做一次迭代搜索
    >>> Card(rank='A', suit='spades') in deck
    True
    

    下面这段就厉害了,弄得我眼黑头晕的,弄了一早上才搞明白,怎么对这些扑克牌进行排序?

    首先你会想到sorted,但我连它的key参数都不会用,何谈去排序这些扑克。sorted用法:

    sorted最简单用法是对元素全部是数字的列表排序,另一种用法是对元素是元组或字典的列表排序

    用到的参数是key,比如:对学生的分数进行排序:

    list1 = [('david', 90), ('mary',90), ('sara',80),('lily',95)]
    sorted(list1, key=lambda x: x[0])  # 按照元组中第一个元素排序
    sorted(list1, key=lambda x: x[1])  # 按照元组中第二个元素排序
    array = [{"age":20,"name":"a"},{"age":25,"name":"b"},{"age":10,"name":"c"}]
    array1 = sorted(array,key=lambda x:x["age"])  # 按照年龄排序

     下面要讲的例子,先抛个砖:

    1.需求:将列表中的元素按照绝对值大小进行升序排列
    list1 = [3,5,-4,-1,0,-2,-6]
    sorted(list1, key=lambda x: abs(x))
    
    当然,也可以如下:
    
    list1 = [3,5,-4,-1,0,-2,-6]
    def get_abs(x):
        return abs(x)
    sorted(list1,key=get_abs)
    只不过这种方式的代码看起来不够Pythonic
    2、应用在闭包中
    def get_y(a,b):
         return lambda x:ax+b
    y1 = get_y(1,1)
    y1(1) # 结果为2
    
    当然,也可以用常规函数实现闭包,如下:
    
    def get_y(a,b):
        def func(x):
            return ax+b
        return func
    y1 = get_y(1,1)
    y1(1) # 结果为2
    只不过这种方式显得有点啰嗦。
    那么是不是任何情况下lambda函数都要比常规函数更清晰明了呢?
    Python之禅中有这么一句话:Explicit is better than implicit(明了胜于晦涩),就是说那种方式更清晰就用哪一种方式,不要盲目的都使用lambda表达式。
    

     扑克牌排序代码:

    suit_values = dict(spades=3, hearts=2, diamonds=1, clubs=0)
    # {'clubs': 0, 'diamonds': 1, 'spades': 3, 'hearts': 2}
    
    def spades_high(card):
        rank_values = FrenchDeck.ranks.index(card.rank)
        return rank_values * len(suit_values) + suit_values[card.suit]
    
    for card in sorted(deck,key=spades_high):
        print(card)
    

    一、这段代码我看了很长时间,这本书的作者竟然将这段代码放在书的第二页,我也是醉了,我觉得是挺难的,但不管怎样,硬着头皮上吧!

    扑克牌排序规则:

    用点数来判断扑克牌的大小,2最小,A最大;同时还要加上对花色的判断:

    黑桃最大,红桃次之,方块再次,梅花最小。那么梅花2的大小是0,黑桃A是51.

    分析一下这个函数:sorted(deck,key=spades_high),我在这里卡了很长时间,所以就有了上面的那块砖,先说一下这个函数是怎么运行的吧:

    通过sorted将deck这一摞牌和排序函数spades_high()联系起来,每张牌都有数字,先获取牌面的数字在FrenchDeck.ranks中的索引,即:2的索引0,

    3的索引1,4的索引2,类推3,4,5,6,7,8,9,10,11,A的索引12,这张牌多大取决于它的花色,即索引 乘 4 加 花色值,

    二、spades_high(card),这里的card就是传进来的每一张牌,rank_values = FrenchDeck.ranks.index(card.rank),

    获取这张纸牌(即纸牌的数字)在FrenchDeck.ranks中的索引,['2', '3', '4', '5', '6', '7', '8', '9', '10', 'J', 'Q', 'K', 'A']

    "最后返回这个牌的得分",rank_values * len(suit_values) + suit_values[card.suit],此时就讲完了么?

    灵光一闪,这个函数返回了所有得分有什么用?sorted()拿到这些得分,怎么把牌排好序?我觉得是这样:

    在得到了[所有得分]这个列表之后,进行排序,得到:[0,1,2,3,4,...51],

    然后将原扑克列表中的元素,一一对应,是怎么对应的?函数在处理的时候应该记录了每张卡的得分,所以能对应上。

    如下(原来的扑克列表可不是这样的,排好序的应该是重新开辟了一个内存空间):

    [Card(rank='2', suit='clubs'),Card(rank='2', suit='diamonds'),Card(rank='2', suit='hearts'),...Card(rank='A', suit='spades')]

     三、比如上面第一块砖:

    list1 = [3,5,-4,-1,0,-2,-6]

    def get_abs(x):
        return abs(x)
    sorted(list1,key=get_abs)

    函数先返回[3,5,4,1,0,2,6],然后排序[0,1,2,3,4,5,6],接着将list1中的每个元素,与排序后的列表对应,

    0不变,1、2变成-1、-2,3不变,4变成-4,5不变,6变成-6,输出[0,-1,-2,3,-4,5,-6]

     四、看不懂的lambda,只是把这两道题放在在这里提醒我,不要迷进去:

    一道面试题:
    list1=[7, -8, 5, 4, 0, -2, -5]
    要求1.正数在前负数在后 2.整数从小到大 3.负数从大到小
    解题思路:先按照正负排先后,再按照大小排先后
    list1=[7, -8, 5, 4, 0, -2, -5]
    print(sorted(list1,key=lambda x:(x<0,abs(x))))
    [7, 5, 4, 0, -8, -2, -5]
    [0, 4, 5, 7, -2, -5, -8]
    
    一个经典的复杂例子 
    这是一个字符串排序,排序规则:小写<大写<奇数<偶数 
    s = ‘asdf234GDSdsf23’  #排序:小写-大写-奇数-偶数 
    print(“”.join(sorted(s, key=lambda x: (x.isdigit(),x.isdigit() and int(x) % 2 == 0,x.isupper(),x)))) 
    原理:先比较元组的第一个值,FALSE
    

       也不说什么脏话了,反正没什么成就感,这些东西耗费我整整一天时间啊,就这本书作者随手扔出来的一些小玩意,搞得我很不堪,

    这就是传说当中的以我之短击他之长吧,法克!但还是会有不服,别人能会,我为什么嫌难,人总是活在矛盾中。总之,以后尽量不搞这些东西了。

  • 相关阅读:
    Android开发总结
    LeakCanary原理分析
    机器学习
    Kivy 中文教程 实例入门 简易画板 (Simple Paint App):2. 实现绘图功能
    Python 零基础 快速入门 趣味教程 (咪博士 海龟绘图 turtle) 3. 循环
    Kivy 中文教程 实例入门 简易画板 (Simple Paint App):1. 自定义窗口部件 (widget)
    Python 零基础 快速入门 趣味教程 (咪博士 海龟绘图 turtle) 2. 变量
    Python 零基础 快速入门 趣味教程 (咪博士 海龟绘图 turtle) 1. 神秘朋友
    Python 零基础 快速入门 趣味教程 (咪博士 海龟绘图 turtle) 0. 准备工作
    远程显示(操作) 服务器 GUI 程序(图形化界面) (基于 X11 Forwarding + Centos + MobaXterm)
  • 原文地址:https://www.cnblogs.com/fawaikuangtu123/p/9768130.html
Copyright © 2020-2023  润新知