本章会(1)讨论一些重要的魔法方法,(2)然后会讨论两个相关的主题:属性和迭代器,(3)最后介绍一个相关的示例来处理一些稍微复杂的问题。
魔法方法或者又称为特殊方法(个人挺不习惯魔法方法的翻译,叫法搞的跟拍科幻片似的,因此后面统一叫做特殊方法),是指被包含下划线的方法或者所能调用到的方法的统称,这些通常会在特殊的情况下调用,并且基本没有手动调用他们的必要。
9.1 注备工作
Python的老版本和新版本在定义类的时候会有些差别,为了统一以新式类的方式来定义类,可以在文件首行添加一行代码来来解决这个问题。个人在2.7的版本上进行学习暂时不存在这个问题,跳过不深究。
9.2 构造方法
构造方法就是类似于init的初始化方法,差别在于一个对象被构建好以后会自动调用构造方法。在Python中创建一个构造方法如下(使用_init_):
class FooBar:
def __init__(self):
self.value = 42
9.2.1 重写一般方法和特殊的构造方法
如果类B继承自类A,类B的某个方法被调用的时候会首先去B中寻找该方法,如果找不到则会到父类中去寻找:
class A():
def hello(self):
print "Hello, I am A!"
class B(A):
pass
a = A()
a.hello()
b = B()
b.hello()
$ python test.py
Hello, I am A!
Hello, I am A!
因为B类没有hello方法,所以当hello被调用时,原始信息就被打印出来。现在类B重写了该方法,再进行调用就能产生不一样的效果:
class A():
def hello(self):
print "Hello, I am A!"
class B(A):
def hello(self):
print "Hello, I am !"
a = A()
a.hello()
b = B()
b.hello()
$ python test.py
Hello, I am A!
Hello, I am B!
重写方法对于类很重要,尤其对构造方法,但重写父类的构造方法需要调用超类的构造方法,否则对象可能不能被正确的初始化。看如下的例子:
class Bird():
def __init__(self):
self.hungry = True
def eat(self):
if self.hungry:
print 'Aaaah...'
self.hungry = False
else:
print 'No, thanks!'
b = Bird()
b.eat()
b.eat()
$ python test.py
Aaaah...
No, thanks!
鸟类在吃过东西以后,就不再饥饿。现在考虑添加SingBird,它添加了唱歌的行为:
class SingBird():
def __init__(self):
self.sound = 'Squawk'
def sing(self):
print self.sound
sb = SingBird()
sb.sing()
$ python test.py
Squawk
但是如果直接调用eat就会产生问题:
Traceback (most recent call last):
File "test.py", line 20, in
sb.eat()
AttributeError: SingBird instance has no attribute 'eat'
为了解决该问题,必须调用超类的构造方法保证正常的初始化,后面两节分别介绍了两种做法。
9.2.2 调用未绑定的超类构造方法
如下为调用未绑定的超类构造方法,属于历史遗留写法:
class SingBird(Bird):
def __init__(self):
Bird.__init__(self)
self.sound = 'Squawk'
def sing(self):
print self.sound
9.2.3 使用super函数
使用super函数的写法:
__metaclass__ = type#super类只能在新式类中使用
class SingBird(Bird):
def __init__(self):
super(SingBird, self).__init__()
self.sound = 'Squawk'
def sing(self):
print self.sound
9.3 成员访问
序列和映射是对象的集合,为了实现它们的基本行为,我们要实现一些魔法