zoukankan      html  css  js  c++  java
  • 《流畅的python》读书笔记,第一章:python数据模型

    这本书上来就讲了魔法方法,也叫双下方法、特殊方法,通过两个例子对让读者了解了双下方法的用法,更重要的是,让我一窥Python的语言风格和给使用者的自由度。

    第一个例子:一摞Python风格的纸牌:

    import collections
    
    Card = collections.namedtuple('Card', ['rank', 'suit'])
    
    
    class FrenchCard:
        ranks = [str(n) for n in range(2, 11)] + list('JQKA')
        suits = 'clubs diamonds hearts spades'.split()
    
        def __init__(self):
            self._cards = [Card(rank, suit) for rank in self.ranks for suit in self.suits]
    
        def __len__(self):
            return len(self._cards)
    
        def __getitem__(self, position):
            return self._cards[position]
    
    
    deck = FrenchCard()
    
    
    suits_values = dict(clubs=0, diamonds=1, hearts=2, spades=3)
    
    
    def high_spades(card):
        ranks_value = FrenchCard.ranks.index(card.rank)
        return ranks_value * len(suits_values) + suits_values[card.suit]
    
    
    for card in sorted(deck, key=high_spades):
        print(card)

    这个例子让我了解到python的许多方法都是由双下方法构成了,比如在这个例子中,如果打印print(deck[0]),会显示Card(rank='2', suit='clubs’),这是因为类里面定义了__getitem__方法,如果没有这个方法的话,就会报错,而且,仅仅实现了__getitem__就可以迭代和反向迭代了。我看了下,list这个类里面也有__getitem__这个方法,那么,如果我们有需求的话,可以定制list里的__getitem__的方法(通过集成和派生)。不过,len这个方法有点特殊,我会在后面讲到哪里特殊。
     
    通过__len__和__getitem__, FrenchDeck这个类,就和Python现有的序列数据类型一样,可以提现出Python的核心语言特性(例如迭代和切片)
     
    另外,namedtuple是一个很好用的函数,用来创建一个只有少量属性,没有方法的类,比单独创建一个类方便多了,感觉和__slots__一点相似,但是没有在实战中用过,以后用到了再去深入了解吧!它的因为解释我觉得很清楚:Returns a new subclass of tuple with named field。
     

    如何使用特殊方法

    特殊方法是为了让Python解释器调用的,你自己并不需要调用它们。也就是说没有 my_object.__len__() 这种写法, 而应该使用 len(my_object)。在执行 len(my_object) 的时候,如果 my_object 是一个自定义类的对象,那么 Python 会自己去调用其中由 你实现的 __len__ 方法。除非使用元编程,否则你的代码通常无需使用特殊方法。
     
    在处理python内置类型的时候,比如列表、字符串、字节等,CPython会走后门,__len__实际是直接返回PyVarObject里的ob_size属性,这个是通过C语言实现的,速度比调用这个方法快很多。
     
    注意,只有是Python自带的数据结构才走这个后门,如果是自己定义的类里有__len__方法的话,是不会走这个后门的。这体现了Python之禅,实用胜于纯粹。len之所以不是一个普通方法(CPython直接从一个C结构体里读取对象的长度),原因是因为我们在编程的时候会大量使用Python自带的数据类型,而同时我们又可以把len用于自定义数据类型。这种处理方式在保持内置类型的效率和 保证语言的一致性之间找到了一个平衡点,也印证了“Python 之禅”中的 另外一句话:“不能让特例特殊到开始破坏既定规则。”
     

    第二个例子:二维向量(vector)

    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)  # x * x + y * 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(1, 2)
    v2 = Vector(2, 3)
    print(v1)  # Vector(1,2)
    
    print(v1 + v2)  # Vector(3,5)
    
    v3 = Vector(0, 0)
    print(bool(v3))  # False

    这个例子使用了6个特殊方法,但是这6个特殊方法并不会在这个类自身的代码中使用,一般只有Python解释器会频繁地直接调用这些方法。
     
    repr方法能把一个对象用字符串的形式表示,在老的使用 % 符号的字符串格式中,这个函数返回的结果用来代 替 %r 所代表的对象。当打印v1的时候会显示Vector(1,2),如果没有__repr__就会显示v1这个对象的内存地址。__repr__和__str__不同的是,使用交互器的时候只有__repr__方法会生效,使用print的时候会先找__str__,没有__str__在去找__repr__。
     
    __add__和__mul__让Vector的对象可以在不改变操作对象的情况下产出一个新的值,实现加法和乘法的运算。
     
    我们自己定义的__bool__的意思是如果一个向量的模是0(x,y都为0),就返回False。bool(v3)调用的就是v3.__bool__(),如果我们没有定义__bool__的话,那么bool(v3)就会去尝试调用v3.__len __(),如果返回0的话,就是False,否则就是True。
     
    下面这种写法会让Vector.__bool__更高效,不过不如第一个好理解,却能省掉从 abs 到 __abs__ 到平方再到平方根这 些中间步骤。 
    def __bool__(self):
            return bool(self.x,self.y)

    Ruby和Python都支持这些特殊方法,Ruby社区称之为魔法方法。Javascript在这方面无法是赶不上Python和Ruby的。

     

  • 相关阅读:
    改造vant日期选择
    css3元素垂直居中
    npm综合
    (转)网页加水印方法
    Mac下IDEA自带MAVEN插件的全局环境配置
    隐藏注册控件窗口
    High performance optimization and acceleration for randomWalk, deepwalk, node2vec (Python)
    How to add conda env into jupyter notebook installed by pip
    The Power of WordNet and How to Use It in Python
    背单词app测评,2018年
  • 原文地址:https://www.cnblogs.com/lshedward/p/10158852.html
Copyright © 2011-2022 走看看