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

  2. MS SqlServer之Exec和EXEC SP_EXECUTESQL

    exec执行sql时字符串时,不能给变量赋值,如果要在sql里给变量赋值,请用EXEC SP_EXECUTESQL 示例: 通过 SP_EXECUTESQL 的第2个参数来定义有哪些参数 输出的加OU ...

  3. memcache和iptables开启11211端口

    linux下安装完memcached后,netstat -ant | grep LISTEN 看到memcache用的11211端口已在监听状态,但建立php文件连接测试发现没有输出结果,iptabl ...

  4. setTimeout() 实现程序每隔一段时间自动执行

    定义和用法 setTimeout() 方法用于在指定的毫秒数后调用函数或计算表达式. 语法 setTimeout(code,millisec) 参数 描述 code 必需.要调用的函数后要执行的 Ja ...

  5. Centos7.2内网环境安装MySQL5.7.24

    1.配置本地yum源 内网环境,首先需要配置本地yum源,以解决MySQL的依赖安装,具体参考该文:点击打开 2.查看服务器环境 uname -a 3.去官网下载MySQL安装包 MySQL官网网址: ...

  6. ruby 正则表达式 匹配中文

    1.puts /[一-龥]+/.match("this is 中文")                 =>中文 2.str2="123中文"puts / ...

  7. 仙人掌(cactus)

    题目描述LYK 在冲刺清华集训(THUSC)!于是它开始研究仙人掌,它想来和你一起分享它最近研究的结果.如果在一个无向连通图中任意一条边至多属于一个简单环(简单环的定义为每个点至多经过一次),且不存 ...

  8. NHibernate中创建User类报错问题

    前两天刚开始学习NHibernate架构,照着前辈的例子打了一遍运行之后没问题,然后自己创建了一个User的Model发现一运行就报User附近有错误,然后就检查,类写的没错用了virtual,Use ...

  9. 【转】pom.xml讲解

    <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/20 ...

  10. Object类-try-catch-finally-throw-throws-自定义异常

    一.Object类     Object类是最顶端的类,其它类都是它的子类,它的方法可以被继承.如果定义的类没有继承别的类,那它的直接父类就是Object.如果方法参数类型为object类型, 则调用 ...