fluent python 第一章小记

Fluent Python 第一章读书笔记

Chapter 1. The Python Data Model

Python数据模型

  • 特殊方法:magic method/dunder method (double underscores (i.e., __getitem__()))
  • 特殊方法使对象能实现,支持基本的语言框架并与之交互,例如:
    • Iteration 迭代
    • Collections 集合
    • Attribute access 访问属性
    • Operator overloading 运算符重载
    • Function and method invocation 函数和方法调用
    • Object creation and destruction 对象的创建和销毁
    • String representation and formatting 字符串表示和格式化
    • Managed contexts (i.e., with blocks) 管理上下文
  • namedtuple的使用:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    >>> import collections
    >>> Card = collections.namedtuple('Card', ['x','y'])
    >>> card = Card(11,22)
    >>> print card.x
    11
    >>> print card.y
    22
    >>> x, y = card
    >>> print x,y
    11 22
  • 使用特殊方法的好处:

    • 类的使用者不需要记忆随意定义的标准方法名。(例如:怎样获取对象中元素的数量,.size()? .length()? 如果用特殊方法__len__()可以直接调用len(object))
    • 类的使用者更容易从Python庞大的标准库中获益,并且可以避免重造轮子(例如:random.choice函数)
    • __getitem__()方法使得类可以进行迭代(iterable),可以进行切片(index slicing)
  • 使用特殊方法需要注意的:

    • 特殊方法不是给人用的,而是给Python解释器用的,一般我们用len(my_obj)而不是my_obj.__len__()
    • 对于list, str, bytearray之类的内置类型,使用len()时,CPython 解释器直接返回PyVarObject的ob_size这个属性的值,这比调用len()方法快得多。PyVarObject是一个代表所有可变长度对象的C语言结构体。
    • 一般对特殊方法的调用都是隐式的,比如for语句隐式地调用了iter()函数
    • 通过内置的函数(例如 len、iter、str,等等)来使用特殊方法是最好的选择。这些内置函数不仅会调用特殊方法,通常还提供额外的好处(上面提到过),而且对于一些内置的类来说,调用函数的速度更快。
    • 不要随意使用特殊方法的命名方式命名一般的方法,可能会造成混淆。
  • 特殊方法使用的举例(构造向量):

    • 对象的字符串表示:如果没有实现__repr__这个特殊方法,控制台就会出现 这样的表示,而如果我们实现了这个方法,控制台就能将对象的详细信息打印出来。
      __repr__方法中可以使用%r 获取不同类型属性的标准字符串表示,比如Vector(1, 2) 或 Vector(‘1’, ‘2’)
      __repr__ 需要尽可能没有歧义,并且提示如何使用类创建相同的变量
      与__str__的不同之处在于, __str__在str()函数或者 print对象时会被调用,__str__用于展示适合展示给终端用户的信息。如果二者只能选其中一个创建,那么__repr__是比较好的选择,因为Python解释器在找不到__str__时会调用__repr__作为替代。(StackOverflow)
    • 算术运算:上面的向量对象使用__add__和__mul__实现了+和*运算。这两个运算的实现都是构造了新的对象,而不是对原来的对象进行改动。实际上这也是中缀运算的基本要求。
    • 布尔运算: Python中的对象在需要的场景(比如if, while)可以作为bool值使用。
      一般用户自定义的对象都被默认为True,但是如果对象实现了__bool__或者__len__,情况就不一样了。如果实现了__bool__,对象的布尔值视为bool()的返回值;如果没有实现__bool__而实现了__len__,那么len()为0的对象就被视为False。
  • 特殊方法一览:
    The Python Language Reference的“Data Model”这一章节列出了83个特殊方法,其中有47个用于实现算术运算,位运算和比较。

  • 小结:

    • 通过实现特殊函数,自定义的对象可以表现得更像是内置的对象,同时使得对象的使用更加便捷,更加Pythonic
    • Python自定义对象的一个基本要求是提供自身的可用的字符串表示。一个用途是开发者用于debug和打印log,另一个用法是终端用户查看对象的信息。这两个功能分别用__repr__和__str__实现
    • 对序列类型的对象的模拟是特殊方法使用最广泛的场景,比如前面提到的FrenchDeck
    • Python 的运算符重载这一模式提供了丰富的数值类型,除了内置的类型之外,还有
      decimal.Decimal 和 fractions.Fraction。这些都支持中缀运算。