#《流畅的Python》读书笔记
# 第一部分 序幕
# 第1章 Python数据模型
# 魔术方法(magic method)是特殊方法的昵称。于是乎,特殊方法也叫双下方法(dunder method)。 # 1.1 一摞Python风格的纸牌

# 示例 1-1 一摞有序的纸牌
import collections Card=collections.namedtuple('Card',['rank','suit']) class FrenchDeck:
ranks=[str(n) for n in range(2,11)]+list('JQKA')
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):
return len(self._cards) def __getitem__(self, position):
return self._cards[position] # 如下面这个控制台会话所示,利用namedtuple,我们可以很轻松地得到一个纸牌对象:
>>> beer_card=Card('','diamond')
>>> beer_card
Card(rank='', suit='diamond') # 首先,它跟任何标准Python集合类型一样,可以用len()函数来查看一叠牌有多少张:
>>> deck=FrenchDeck()
>>> len(deck)
52 #从一叠牌中抽取特定的一张纸牌,比如说第一张或最后一张,是很容易的:deck[0]或deck[-1]。这都是由__getitem__方法提供的:
>>> deck[0]
Card(rank='', suit='spades')
>>> deck[-1]
Card(rank='A', suit='hearts') #Python 已经内置了从一个序列中随机选出一个元素的函数random.choice
>>> from random import choice
>>> choice(deck)
Card(rank='J', suit='hearts')
>>> choice(deck)
Card(rank='', suit='clubs')
>>> choice(deck)
Card(rank='', suit='diamonds') #下面列出了查看一摞牌最上面3张和只看牌面是A的牌的操作。
>>> deck[:3]
[Card(rank='', suit='spades'), Card(rank='', suit='spades'), Card(rank='', suit='spades')]
>>> 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)
Card(rank='', suit='spades')
Card(rank='', suit='spades')
Card(rank='', suit='spades')
Card(rank='', suit='spades')
... #反向迭代也没关系:
>>> for card in reversed(deck):
print(card)
Card(rank='A', suit='hearts')
Card(rank='K', suit='hearts')
Card(rank='Q', suit='hearts')
Card(rank='J', suit='hearts')
... #in运算符就会按顺序做一次迭代搜索
>>> Card('Q','hearts') in deck
True
>>> Card('','beats') in deck
False #梅花2的大小是0,黑桃A是51:
>>> suit_values=dict(spades=3,hearts=2,diamonds=1,clubs=0)
>>> def spades_high(card):
rank_value=FrenchDeck.ranks.index(card.rank)
return rank_value*len(suit_values)+suit_values[card.suit] #有了spades_high函数,就能对这摞牌进行升序排序了:
>>> for card in sorted(deck,key=spades_high):
print(card)
Card(rank='', suit='clubs')
Card(rank='', suit='diamonds')
Card(rank='', suit='hearts')
Card(rank='', suit='spades')
Card(rank='', suit='clubs')
... # 1.2 如何使用特殊方法
# 首先明确一点,特殊方法的存在是为了被Python解释器调用的,你自己并不需要调用它们。也就是说没有my_object.__len__()这种写法,而应该使用len(my_object)。在执行len(my_object)的时候,如果my_object是一个自定义类的对象,那么Python会自己去调用其中由你实现的__len__方法。

# 很多时候,特殊方法的调用是隐式的,比如for i in x:这个语句,背后其实用的是iter(x),而这个函数的背后则是x.__iter__()方法。当然前提是这个方法在x中被实现了。 # 通常你的代码无需直接使用特殊方法。除非有大量的元编程存在,直接调用特殊方法的频率应该远远低于你去实现它们的次数。唯一的例外可能是__init__方法,你的代码里可能经常会用到它,目的是在你自己的子类的__init__方法中调用超类的构造器。 # 通过内置的函数(例如len、iter、str,等等)来使用特殊方法是最好的选择。这些内置函数不仅会调用特殊方法,通常还提供额外的好处,而且对于内置的类来说,它们的速度更快。14.12节中有详细的例子。 # 不要自己想当然地随意添加特殊方法,比如__foo__之类的,因为虽然现在这个名字没有被Python内部使用,以后就不一定了。 #示例 1-2 一个简单的二维向量类
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) # 如果想让Vector.__bool__更高效,可以采用这种实现:
# def __bool__(self):
# return bool(self.x or self.y) def __bool__(self):
return bool(abs(self)) def __add__(self, other):
x=self.x+other.x
y=self.y+other.y def __mul__(self,scalar):
return Vector(self.x*scalar,self.y*scalar) #为了给这个类型设计API,我们先写个模拟的控制台会话来做doctest. #下面这一段代码就是向量加法:
>>> v1 = Vector(2, 4)
>>> v2 = Vector(2, 1)
>>> v1 + v2
Vector(4, 5) #为了保持一致性,我们的API在碰到abs函数的时候,也应该返回该向量的模:
>>> v = Vector(3, 4)
>>> abs(v)
5.0 #我们还可以利用*运算符来实现向量的标量乘法:
>>> v * 3
Vector(9, 12)
>>> abs(v * 3)
15.0 # Python有一个内置的函数叫repr,它能把一个对象用字符串的形式表达出来以便辨认,这就是“字符串表示形式”。
# repr就是通过 __repr__这个特殊方法来得到一个对象的字符串表示形式的。
# 如果没有实现__repr__,当我们在控制台里打印一个向量的实例时,得到的字符串可能会是<Vector object at 0x10e100070>。
# __repr__和__str__的区别在于,后者是在str()函数被使用,或是在用print函数打印一个对象的时候才被调用的,并且它返回的字符串对终端用户更友好。 # 1.3 特殊方法一览
# 表1-1:跟运算符无关的特殊方法
# 表1-2:跟运算符相关的特殊方法 # 1.4 为什么len不是普通方法
# 换句话说,len之所以不是一个普通方法,是为了让Python自带的数据结构可以走后门,abs也是同理。
# 但是多亏了它是特殊方法,我们也可以把len用于自定义数据类型。
# 这种处理方式在保持内置类型的效率和保证语言的一致性之间找到了一个平衡点,也印证了“Python之禅”中的另外一句话:“不能让特例特殊到开始破坏既定规则。” # 1.5 本章小结
# 通过实现特殊方法,自定义数据类型可以表现得跟内置类型一样,从而让我们写出更具表达力的代码——或者说,更具Python风格的代码。 # Python对象的一个基本要求就是它得有合理的字符串表示形式,我们可以通过__repr__和__str__来满足这个要求。前者方便我们调试和记录日志,后者则是给终端用户看的。这就是数据模型中存在特殊方法__repr__和__str__的原因。 # 对序列数据类型的模拟是特殊方法用得最多的地方,这一点在FrenchDeck类的示例中有所展现。在第2章中,我们会着重介绍序列数据类型,然后在第10章中,我们会把Vector类扩展成一个多维的数据类型,通过这个练习你将有机会实现自定义的序列。 # Python通过运算符重载这一模式提供了丰富的数值类型,除了内置的那些之外,还有decimal.Decimal和fractions.Fraction。这些数据类型都支持中缀算术运算符。在第13章中,我们还会通过对Vector类的扩展来学习如何实现这些运算符,当然还会提到如何让运算符满足交换律和增强赋值。 #Python数据模型的特殊方法还有很多,本书会涵盖其中的绝大部分,探讨如何使用和实现它们。 # 1.6 延伸阅读

第1章 Python数据模型的更多相关文章

  1. 流畅的python第一章python数据模型学习记录

    python中有些特殊的方法,以双上下划线开头,并以双下划线结束的方法.如__getitem__,这些方法是特殊的方法,供python解释权内部使用,一般来说不需要调用 还有一种是以双下划线开头的,如 ...

  2. 《流畅的Python》 第一部分 序章 【数据模型】

    流畅的Python 致Marta,用我全心全意的爱 第一部分 序幕 第一章 Python数据模型 特殊方法 定义: Python解释器碰到特殊句法时,使用特殊方法激活对象的基本操作,例如python语 ...

  3. [Python学习笔记][第七章Python文件操作]

    2016/1/30学习内容 第七章 Python文件操作 文本文件 文本文件存储的是常规字符串,通常每行以换行符'\n'结尾. 二进制文件 二进制文件把对象内容以字节串(bytes)进行存储,无法用笔 ...

  4. [Python学习笔记][第五章Python函数设计与使用]

    2016/1/29学习内容 第四章 Python函数设计与使用 之前的几页忘记保存了 很伤心 变量作用域 -一个变量已在函数外定义,如果在函数内需要修改这个变量的值,并将这个赋值结果反映到函数之外,可 ...

  5. [Python学习笔记][第四章Python字符串]

    2016/1/28学习内容 第四章 Python字符串与正则表达式之字符串 编码规则 UTF-8 以1个字节表示英语字符(兼容ASCII),以3个字节表示中文及其他语言,UTF-8对全世界所有国家需要 ...

  6. [Python笔记][第四章Python正则表达式]

    2016/1/28学习内容 第四章 Python字符串与正则表达式之正则表达式 正则表达式是字符串处理的有力工具和技术,正则表达式使用预定义的特定模式去匹配一类具有共同特征的字符串,主要用于字符串处理 ...

  7. [Python笔记][第二章Python序列-复杂的数据结构]

    2016/1/27学习内容 第二章 Python序列-复杂的数据结构 堆 import heapq #添加元素进堆 heapq.heappush(heap,n) #小根堆堆顶 heapq.heappo ...

  8. [Python笔记][第二章Python序列-tuple,dict,set]

    2016/1/27学习内容 第二章 Python序列-tuple tuple创建的tips a_tuple=('a',),要这样创建,而不是a_tuple=('a'),后者是一个创建了一个字符 tup ...

  9. [python笔记][第二章Python序列-list]

    2016/1/27学习内容 第二章 Python序列-list list常用操作 list.append(x) list.extend(L) list.insert(index,x) list.rem ...

随机推荐

  1. Codeforces Beta Round #34 (Div. 2)

    Codeforces Beta Round #34 (Div. 2) http://codeforces.com/contest/34 A #include<bits/stdc++.h> ...

  2. redis 简介,安装与部署

    NOSQL简介 NoSQL,泛指非关系型的数据库,NoSQL数据库的四大分类: 键值(Key-Value)存储数据库:这一类数据库主要会使用到一个哈希表,这个表中有一个特定的键和一个指针指向特定的数据 ...

  3. vue 路由参数变化,页面不更新的问题

    监控$route 在vue项目中,假使我们在同一个路由下,只是改变路由后面的参数值,如果不监听路由参数值的变化,页面无数据刷新,需手动刷新浏览器,这样做就不是我们的预期效果. 举例:当前路由为  /p ...

  4. PTA 7-6 列出连通集(深搜+广搜)

    给定一个有N个顶点和E条边的无向图,请用DFS和BFS分别列出其所有的连通集.假设顶点从0到N−1编号.进行搜索时,假设我们总是从编号最小的顶点出发,按编号递增的顺序访问邻接点. 输入格式: 输入第1 ...

  5. java 动手动脑解决问题

    1.Java的基本运行单位是类还是方法?是类,因为没有方法可以独立存在,方法在逻辑上属于类或属于对象. 2.类的组成成员?成员变量,成员方法. 3.成员变量的种类? byte short int lo ...

  6. 利用Java创建Windows服务

    1.Java测试代码 import org.apache.log4j.Logger; public class Test { private static Logger logger = Logger ...

  7. c# ?. 空值传播运算符

    当左侧为空时不执行右侧代码,避免出现为null的错误,同时也避免了判断是否为null,可以和??一起连用,省了好多事.举例如下: 以前:var res=obj==null?5:obj.a; 现在:va ...

  8. vuex,文件夹整理

    不多说直接上图 1,执行事件和调用 2添加模块 3模块内执行过程

  9. css 边距等常用设置

    前端知识 <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF- ...

  10. 5A - 超级楼梯

    有一楼梯共M级,刚开始时你在第一级,若每次只能跨上一级或二级,要走上第M级,共有多少种走法? Input 输入数据首先包含一个整数N,表示测试实例的个数,然后是N行数据,每行包含一个整数M(1< ...