魔法(特殊)方法、特性和迭代器
在Python中,有些名称很特别,开头和结尾都是两个下划线。在这样的名称中,很大一部分都是魔法(特殊)方法的名称。如果你的对象实现了这些方法,它们将在特定情况下被Python调用,而几乎不需要直接调用。
本章讨论几个重要的魔法方法,其中重要的是**__init__以及一些处理元素访问的方法(它们能让你能够创建序列或映射)**。本章还讨论两个相关的主题:特性(property)和迭代器(iterator)。特性通过函数property处理,迭代器使用魔法方法__iter__,让其可以使用在for循环中。
1、构造函数
第一个魔法方法是构造函数,构造函数不同于普通方法的地方在于,将在对象创建后自动调用它们。创建构造函数只需要将init方法的名称从普通的init改为魔法版的**__init__**即可。
class FooBar:
def __init__(self):
self.somevar = 42
f = FooBar()
print(f.somevar) #42
构造函数中也可以添加参数:
class FooBar:
def __init__(self,value = 43):
self.somevar = value
f = FooBar()
print(f.somevar) #43
f = FooBar('This is a constructor argument')
print(f.somevar) #This is a constructor argument
注意:Python还提供了__del__析构函数,不过不能确定具体的销毁时间,所以最好不要使用这个方法。
1.1、重写普通方法和特殊的构造方法
每个类都有一个或多个超类,并从他们那继承行为。对类B的实例调用方法(或访问其属性)时,如果找不到该方法(或属性),将在其超类A中查找。
class A:
def hello(self):
print("Hello,I'm A")
class B(A):
pass
a = A()
b = B()
a.hello() #Hello,I'm A
#由于B类没有自己的方法hello,所以调用hello时,打印的是A类的信息
b.hello() #Hello,I'm A
要在子类中添加功能,一种基本方式是添加方法,然而,你可以重写超类中的某些方法,以定制继承来的行为:
class B(A):
def hello(self):
print("Hello,I'm B")
b = B()
b.hello() #Hello,I'm B
重写是继承机制的一个重要方面,对构造函数来说尤其重要。构造函数用于初始化新建对象的状态,而对于大多数子类来说,除超类的初始化代码外,还需要有自己的初始化代码。但与普通方法相比,重写构造函数时更有可能遇到一个特别的问题:重写构造函数时,必须调用超类的构造函数,否则无法正确地初始化对象。
class Bird():
def __init__(self):
self.hungry = True
def eat(self):
if self.hungry:
print("Aaah...")
self.hungry = False
else:
print("No,thanks!")
class SongBird(Bird):
def __init__(self):
self.sound = "Squawk!"
def sing(self):
print(self.sound)
sb = SongBird()
sb.sing() #Squawk!
#但如果调用eat方法,将发现一个问题
sb.eat()
#AttributeError: 'SongBird' object has no attribute 'hungry'
为什么会这样呢?因为在SongBird中重写了构造函数,但新的构造函数没有包含任何初始化属性hungry的代码。要消除这样的错误,SongBird必须调用其超类的构造函数,为此,可以有两种方法:1、调用未关联的超类的构造函数;2、使用函数super。
1.1.1、调用未关联的超类的构造方法
class SongBird(Bird):
def __init__(self):
Bird.__init__(self) #添加了这一行
self.sound = "Squawk!"
def sing(self):
print(self.sound)
sb = SongBird()
sb.sing()