这本书上来就讲了魔法方法,也叫双下方法、特殊方法,通过两个例子对让读者了解了双下方法的用法,更重要的是,让我一窥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的。

《流畅的python》读书笔记,第一章:python数据模型的更多相关文章

  1. [Python笔记][第一章Python基础]

    2016/1/27学习内容 第一章 Python基础 Python内置函数 见Python内置函数.md del命令 显式删除操作,列表中也可以使用. 基本输入输出 input() 读入进来永远是字符 ...

  2. Python笔记·第一章—— Python基础(一)

    一.Python的简介 1.Python的由来与版本 1.1 python的由来 python的创始人为吉多·范罗苏姆(Guido van Rossum).1989年的圣诞节期间,吉多·范罗苏姆(中文 ...

  3. 《css3实战》读书笔记 第一章 基于CSS需求而编写的HTML.

    笔记说明 <CSS3实战手册第3版(影印版)>可以消除Web设计工作的痛苦,并且带给你:HTML--重新入门.如果你是HTML新手,你会学到如何以CSS友好的方式进行基本页面构造.若你是H ...

  4. 《疯狂Java:突破程序员基本功的16课》读书笔记-第一章 数组与内存控制

    很早以前就听过李刚老师的疯狂java系列很不错,所以最近找一本拿来拜读,再此做下读书笔记,促进更好的消化. 使用Java数组之前必须先对数组对象进行初始化.当数组的所有元素都被分配了合适的内存空间,并 ...

  5. Getting Started With Hazelcast 读书笔记(第一章)

    第一章:数据集群的演化与 早期的服务器架构 显然,应用是可扩展的,但是由于是集中式服务器,随着数据库性能达到极限,再想扩展就变得极端困难,于是出现了缓存.    缓存显然再次提升了可扩展性,减轻了数据 ...

  6. .net架构设计读书笔记--第一章 基础

    第一章 基础 第一节 软件架构与软件架构师  简单的说软件架构即是为客户构建一个软件系统.架构师随便软件架构应运而生,架构师是一个角色. 2000年9月ANSI和IEEE发布了<密集性软件架构建 ...

  7. C缺陷与陷阱----读书笔记---第一章

    第一章:词法陷阱 编译器中负责将程序分解为一个一个符号的部分,一般称为“词法分析器”.例如,对于语句: if ( x == big ) big = x ; 它的第一个符号是C语言关键字if,紧接着下一 ...

  8. 《C++ Primer》读书笔记 第一章

    读<C++ Primer>才知道,自己对C++知之甚少... 写个博客记录下自己C++的成长,只是读书笔记,不是对<C++ Primer>知识点的总结,而是对自己在书上看到的以 ...

  9. 《深入理解计算机系统》(CSAPP)读书笔记 —— 第一章 计算机系统漫游

    本章通过跟踪hello程序的生命周期来开始对计算机系统进行学习.一个源程序从它被程序员创建开始,到在系统上运行,输出简单的消息,然后终止.我们将沿着这个程序的生命周期,简要地介绍一些逐步出现的关键概念 ...

  10. 流畅的python 读书笔记 第二章 序列构成的数组 列表推导

    列表推导是构建列表(list)的快捷方式,而生成器表达式则可以用来创建其他任何类型的序列.如果你的代码里并不经常使用它们,那么很可能你错过了许多写出可读性更好且更高效的代码的机会. 2.2.1 列表推 ...

随机推荐

  1. 漫谈Code Review的错误实践

    从刚开始工作时到现在,已经写了7年的代码,大部分代码都被人review过,自己也review了很多人的代码.在上一家公司的时候,我负责的一轮面试是专门进行Code Review的练习和经验谈. 通过在 ...

  2. Flash图表FusionCharts如何自定义图表导出菜单或界面

    FusionCharts的导出组件界面有两种模式: Compact Mode: 用于保存单张图片,每一个单独的导出组件实例都代表单独的图表.在这种模式下,只有一个按钮和标题是可见的. Full Mod ...

  3. ptxas fatal : Unresolved extern function Error 255

    This question already has an answer here: External calls are not supported - CUDA 1 answer I am tryi ...

  4. ABAP,Java和JavaScript的序列化,反序列化

    ABAP 1. ABAP提供了一个工具类cl_proxy_xml_transform,通过它的两个方法abap_to_xml_xstring和xml_xstring_to_abap实现两种格式的互换. ...

  5. UVA 12901 Refraction 折射 (物理)

    一道物理题,解个2次方程就行了... 求h最小的情况对应如下图所示 做法不唯一,我想避免精度损失所以在化简的时候尽可能地去避免sqrt和浮点数乘除. 似乎精度要求很低,直接用角度算也可以 #inclu ...

  6. Spark性能调优之道——解决Spark数据倾斜(Data Skew)的N种姿势

    原文:http://blog.csdn.net/tanglizhe1105/article/details/51050974 背景 很多使用Spark的朋友很想知道rdd里的元素是怎么存储的,它们占用 ...

  7. 在CNN中使用Tensorflow进行数据增强

    开始之前,需要思考一些基本问题 1.为什么需要大量数据 当您训练机器学习模型时,您真正在做的是调整其参数,以便它可以将特定输入(例如,图像)映射到某个输出(标签).我们的优化目标是追逐我们模型损失较低 ...

  8. 树莓派 - 修改pi账号密码,开启root账号

    1.修改PI账号的密码 password pi 2.开启root账号 树莓派使用的Linux是debian系统,所以树莓派启用root和debian是相同的. debian里root账户默认没有密码, ...

  9. SC || 解决在git中上传过大文件的问题(如何将提交过的彻底删除

    就在我在ddl前续命的时候……不知道怎么想不开,把v2的压力测试的日志(500多M)也往github上传 之前听说过好多因为传了大文件的锅…… 我竟然还想不开的往上传…… 真实又傻又蠢又自闭(T T ...

  10. ovx openVirtex的阅读文档

    由于flowvisor只有4个版本, 最新更新都是2013年的, 跟底层ovs版本不跟进, 最近斯坦福post一个 ovx, 猜测是flowvisor的加强版, 所以看一下文档说明 文档详见http: ...