流畅的Python 第一章
作者:互联网
# 流畅的Python 第一章
1. **数据模型** 其实是对 Python 框架的描述,它规范了这门语言自身构建模块的**接口**,这些模块包括但不限于**序列**、**迭代器**、**函数**、**类**和**上下文管理器**。
2. Python 解释器碰到特殊的句法时,会使用特殊方法去激活一些基本的对象操作,这些特殊方法的名字以**两个下划线**开头,以两个下划线结尾(例如`__getitem__`)。比如 `obj[key]` 的背后就是 `__getitem__` 方法,为了能求得`my_collection[key]` 的值,解释器实际上会调用 `my_collection.__getitem__(key)`。
3. **魔术方法**( `magic method`)是**特殊方法**的昵称。`__getitem_`了 **双下- getitem**( `dunder-getitem` )这种说法。于是乎,特殊方法也叫**双下方法**( `dunder method` )。
4. 现在已经可以体会到通过实现特殊方法来利用Python数据模型的两个好处。作为你的类的用户,他们不必去记住标准操作的各式名称(“怎么得到元素的总数?是.size( )还是.length( )还是别的什么?”)。可以更加方便地利用Python的标准库,比如random.choice函数,从而不用重新发明轮子。
5. 虽然FrenchDeck隐式地继承了object类,[插图]但功能却不是继承而来的。我们通过数据模型和一些合成来实现这些功能。通过实现__len__和__getitem__这两个特殊方法,FrenchDeck就跟一个Python自有的序列数据类型一样,可以体现出Python的核心语言特性(例如迭代和切片)。同时这个类还可以用于标准库中诸如random.choice、reversed和sorted这些函数。另外,对合成的运用使得__len__和__getitem__的具体实现可以代理给self._cards这个Python列表(即list对象)。
6. 按照目前的设计,FrenchDeck是不能洗牌的,因为这摞牌是不可变的(immutable):卡牌和它们的位置都是固定的,除非我们破坏这个类的封装性,直接对_cards进行操作。第11章会讲到,其实只需要一行代码来实现__setitem__方法,洗牌功能就不是问题了。
7. **特殊方法** 的存在是为了被 **Python 解释器** 调用的,没有 `my_object.__len__()`这种写法,而应该使用`len(my_object)`。在执行 `len(my_object)` 的时候,如果 `my_object` 是一个**自定义类**的对象,那么 `Python` 会去调用自定义类中实现的 `__len__` 方法。
8. 如果是 Python **内置**的类型,比如**列表**(list)、字符串(str)、字节序列(bytearray)等,那么CPython会抄个近路,`__len__` 实际上会直接返回 `PyVarObject` 里的 `ob_size` 属性。`PyVarObject` 是表示**内存中长度可变**的内置对象的C语言结构体。直接读取这个值比调用一个方法要快很多。
9. 很多时候,特殊方法的调用是隐式的,比如 `for i in x:` 这个语句,背后其实用的是 `iter(x)`,而这个函数的背后则是 `x.__iter__()` 方法。当然前提是这个方法在 `x` 中被实现了。
10. abs是一个内置函数,如果输入是整数或者浮点数,它返回的是输入值的绝对值;如果输入是复数(complex number),那么返回这个复数的模。
11. Python 有一个内置的函数叫 `repr`,它能把一个**对象**用**字符串**的形式表达出来以便辨认,这就是**字符串表示形式**。`repr` 就是通过 `__repr__` 这个特殊方法来得到一个**对象的字符串表示形式**的。如果没有实现 `__repr__`,当我们在控制台里打印一个向量的实例时,得到的字符串可能会是 `<Vector object at0x10e100070>`。
12. 在 `__repr__` 的实现中,我们用到了 `%r` 来获取对象各个属性的标准字符串表示形式——这是个好习惯,它暗示了一个关键:Vector(1, 2)和Vector('1', '2')是不一样的
13. `__repr__` 和 `__str__` 的区别在于,后者是在 `str()` 函数被使用,或是在用 `print` 函数打印一个对象的时候才被调用的,并且它返回的字符串对终端用户更友好。如果你只想实现这两个特殊方法中的一个,`__repr__` 是更好的选择,因为如果一个对象没有 `__str__` 函数,而 `Python` 又需要调用它的时候,解释器会用 `__repr__` 作为替代。
14. 尽管Python里有bool类型,但实际上任何对象都可以用于需要布尔值的上下文中(比如if或while语句,或者and、or和not运算符)。为了判定一个值x为真还是为假,Python会调用bool(x),这个函数只能返回True或者False。默认情况下,我们自己定义的类的实例总被认为是真的,除非这个类对__bool__或者__len__函数有自己的实现。bool(x)的背后是调用x.__bool__( )的结果;如果不存在__bool__方法,那么bool(x)会尝试调用x.__len__( )。若返回0,则bool会返回False;否则返回True。
15. 通过实现特殊方法,自定义数据类型可以表现得跟内置类型一样,从而让我们写出更具表达力的代码——或者说,更具Python风格的代码。
标签:__,流畅,Python,repr,len,第一章,getitem,方法 来源: https://www.cnblogs.com/liuxiaocs/p/15744453.html