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

    公司的数据库挂了查了下 ,每个表都有自己独立的表空间,有一张表的ibd 文件有好几G了.然后想要释放它. 解决方案: 第一种,删除表,然后重新建.drop table 操作自动回收表空间 第二种,al ...

  2. sql-monitore 的bug 。

    http://www.mamicode.com/info-detail-1659243.html 存储过程无法做 sql -monitor , 而存储过程跑的sql (只能通过awr 报告来看sql_ ...

  3. C - AtCoDeerくんと選挙速報 / AtCoDeer and Election Report

    ceil有毒啊..用ceil一直错. 思路就是模拟吧,设当前的答案是ansx和ansy. 如果比例是小于ansx的,那么就要乘以一个倍数k1,使得a * k1 >= ansx的. 所以就用cei ...

  4. (转)io优化

    原文:http://blog.csdn.net/gzh0222/article/details/9227393 1.系统学习 IO性能对于一个系统的影响是至关重要的.一个系统经过多项优化以后,瓶颈往往 ...

  5. CQRS之旅——旅程4(扩展和增强订单和注册限界上下文)

    旅程4:扩展和增强订单和注册限界上下文 进一步探索订单和注册的有界上下文. "我明白,如果一个人想看些新鲜的东西,旅行并不是没有意义的."儒勒·凡尔纳,环游世界80天 对限界上下文 ...

  6. Java微信公众平台开发(十一)--微信JSSDK中Config配置

    JSSDK曾经引爆前端以及后端的工程师,其魔性的力量毋庸置疑,在我们的技术眼里它的实现原理和根本是不能够被改变的,这篇文章就不对其js的实现做任何评价和解说了(因为我也不是很懂,哈哈),这里要说的是它 ...

  7. LCA 离线做法tarjan

    tarjan(int u) { int v; for(int i=h[u];i;i=nex[i])//搜索边的 { v=to[i]; tarjan(v); marge(u,v); vis[v]=; } ...

  8. 一、Postgresql的基本操作

    ---------------------------------------------------------------------------------------------------- ...

  9. 9、调整数组顺序使奇数位于偶数前面------------>剑指offer系列

    题目描述 输入一个整数数组,实现一个函数来调整该数组中数字的顺序,使得所有的奇数位于数组的前半部分,所有的偶数位于数组的后半部分,并保证奇数和奇数,偶数和偶数之间的相对位置不变. 思路 首先寻找第一个 ...

  10. Each soul is individual and has its own merits and faults.

    Each soul is individual and has its own merits and faults. 每一个灵魂都是独特的,都有各自的美德和过错.<摆渡人>