您的位置:首页 > 编程语言 > Python开发

《Python基础教程》读书笔记(4)之第9章魔法方法、属性和迭代器(关键词:Python/魔法方法/属性/迭代器)

2017-09-15 15:59 513 查看

第9章 魔法方法、属性和迭代器

在Python中,有点名称会在前面和后面都加上两个下划线,这种拼写表示名字有特殊含义,所以绝对不要在自己的程序中使用这种名字。由这些名字组成的集合所包含的方法称为魔法(或称特殊)方法。如果对象实现了这些方法中的某一个,那么这个方法会在特殊的情况下(确切地说是根据名字),被Python调用。而几乎没有直接调用它们的必要。

9.1 准备工作

class NewStyle(object):
more_code_here
class OldStyle:
more_code_here


NewStyle是新式的类,OldStyle是旧式的类。如果文件以
__metaclass__
=type开始,那么两个类都是新式类。

注意 Python3.0中,没有“旧式”的类,也不需要显式地子类化object或者将元类设置为type。所有的类都会隐式地成为object的子类——如果没有明确超类的话,就会直接子类化;否则会简介子类化。

9.2 构造方法

在Python中创建一个构造方法很容易。只要把init方法的名字从简单的init修改为魔法版本
__init__
即可:

class FooBar:
def __init__(self):
self.somevar = 42
>>> f = FooBar()
>>> f.somevar
42


注意 Python中有一个魔法方法叫做
__del__
,也就是析构方法。它在对象就要被垃圾回收之前调用。但发生调用的具体时间是不可知的。所以建议尽力避免使用
__del__
函数。

9.2.1 重写一般方法和特殊的构造方法

每个类都可能拥有一个或者多个超类,它们从超类那里继承行为方式。如果一个方法在B类的一个实例中被调用(或一个属性被访问),但在B类中没有找到该方法,那么就会去它的超类A里面找。

class A:
def hello(self):
print "hello, i'm A"
class B:
pass


>>> a = A()
>>> b = B()
>>> a.hello()
hello, i'm A
>>> b.hello()
hello, i'm A


因为B类没有定义自己的hello方法,所以,当hello被调用时,原始的信息被打印出来。

在子类中增加功能的最基本的方式是增加方法。

但是也可以重写一些超类的方法来自己定义继承的行为。

class B(A):
def hello(self):
print "hello, i'm B"


重写是继承机制中的一个重要内容,对于构造方法尤其重要。构造方法用来初始化新创建对象的状态,大多数子类不仅要拥有自己的初始化代码,还要拥有超类的初始化代码。问题:如果一个类的构造方法被重写,那么就需要调用超类(你说继承的类)的构造方法,否则对象可能不会被正确地初始化。

以下是一个Bird类:

__metaclass__ = type

class Bird:
def __init__(self):
self.hungry = True
def eat(self):
if self.hungry:
print 'i want to eat'
self.hungry = False
else:
print 'no, i am full'


>>> b = Bird()
>>> b.eat()
i want to eat
>>> b.eat()
no, i am full


现在考虑子类SongBird,它添加了唱歌的行为。

class SongBird(Bird):
def __init__(self):
self.sound = 'yinyinyin!'
def sing(self):
print self.sound


>>> sb = SongBird()
>>> sb.sing()
yinyinyin!
>>> sb.eat()

Traceback (most recent call last):
File "<pyshell#6>", line 1, in <module>
sb.eat()
File "/home/henry/dev/Python_Basic_Course/chapter9_magicMethod_attribute_iterator/classBirdDemo.py", line 7, in eat
if self.hungry:
AttributeError: 'SongBird' object has no attribute 'hungry'


异常清楚地说明了错误:SongBird没有hungry特性。原因是这样的:在SongBird中,构造方法被重写,但新的构造方法没有任何关于初始化hungry特性的代码。为了达到预期的效果,SongBird的构造方法必须调用其超类Bird的构造方法来确保进行基本的初始化。有两种方法能达到这个目的:调用超类构造方法的未绑定版本,或者使用super函数。

9.2.2 调用未绑定的超类构造方法

__metaclass__ = type
class SongBird(Bird):
def __init__(self):
Bird.__init__(self)
self.sound = 'yinyinyin!'
def sing(self):
print self.sound


SongBird类中只添加了一行代码——
Bird.__init__(self)


>>> sb = SongBird()
>>> sb.eat()
i want to eat
>>> sb.eat()
no, i am full
>>> sb.sing()
yinyinyin!


书上的解释我没看懂,关于添加的一行代码,这里我的理解是,将超类(所继承的类)的构造方法(Bird类的
__init__
方法)继承过来,暂时没时间去理解了,先这样吧。

9.2.3 使用super函数

super函数只能在新式类中使用,但不管怎样,都应该使用新式类。当前的类和对象可以作为super函数的参数使用,调用函数返回的对象的任何方法都是调用超类的方法,而不是当前类的方法。那么可以直接使用super(SongBird,self)。

如下是对Bird类例子的更新:

__metaclass__ = type

class Bird:
def __init__(self):
self.hungry = True
def eat(self):
if self.hungry:
print 'i want to eat'
self.hungry = False
else:
print 'no, i am full'

class SongBird(Bird):
def __init__(self):
super(SongBird, self).__init__()
self.sound = 'yinyinyin!'
def sing(self):
print self.sound


9.3 成员访问

本节会讨论一个有用的魔法方法集合,可以创建行为类似于序列或映射的对象。

注意 协议(protocol)这个词在Python中会经常使用,它是管理某种形式的行为的规则。协议说明了应该实现何种方法和这些方法应该做什么。因为Python中的多态性是基于对象的行为的(而不是基于祖先,例如它所属的类或者超类,等等)。

9.3.1 基本的序列和映射协议

序列和映射是对象(items)的集合(collections)。为了实现它们的基本的行为(协议),如果对象是不可变的,那么就需要使用两个魔法方法,如果是可变的则需要使用4个。

__len__(self)
:这个方法应该返回集合中所含项目的数量。详细见书上。

__getitem__(self,key)
:这个方法返回与所给键对应的值。详细见书上。

__setitem__(self,key,value)
:这个方法应该按一定的方式存储和key相关的value,该值随后可使用
__getitem__
来获取。当然,只能为可变对象定义这个方法。详细见书上。

__delitem__(self,key)
:这个方法在对一部分对象使用del语句时被调用,同时必须删除和元素相关的键。这个方法也是为可变对象定义的。详细见书上。

!!!这本书的中文翻译相当稀烂!!!我看不下去了,换书!!!要不然就去看英文原版,妈的!!!

参考文献:

1.《Python基础教程(第2版·修订版)》。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息